diff --git a/.classpath b/.classpath
index 62fd5b9..317546f 100644
--- a/.classpath
+++ b/.classpath
@@ -1,11 +1,13 @@
-
+
+
+
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
index af1b6ea..af07d5f 100644
--- a/.settings/org.eclipse.jdt.core.prefs
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -1,12 +1,12 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.release=enabled
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/lib/jdatepicker-1.3.4.jar b/lib/jdatepicker-1.3.4.jar
new file mode 100644
index 0000000..a716259
Binary files /dev/null and b/lib/jdatepicker-1.3.4.jar differ
diff --git a/lib/mysql-connector-j-8.4.0.jar b/lib/mysql-connector-j-8.4.0.jar
new file mode 100644
index 0000000..8294fe0
Binary files /dev/null and b/lib/mysql-connector-j-8.4.0.jar differ
diff --git a/src/client/AssignBox.java b/src/client/AssignBox.java
new file mode 100644
index 0000000..26aac1d
--- /dev/null
+++ b/src/client/AssignBox.java
@@ -0,0 +1,98 @@
+package client;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
+import task.TaskAssignment;
+
+public class AssignBox extends JFrame {
+ private JList taskList;
+ private DefaultListModel taskListModel;
+ private JTextArea taskDetails;
+ private JButton acceptButton;
+ private JButton rejectButton;
+
+ public AssignBox() {
+ setTitle("Assigned Tasks");
+ setSize(400, 300);
+ setLayout(new BorderLayout());
+
+ taskListModel = new DefaultListModel<>();
+ taskList = new JList<>(taskListModel);
+ taskList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ taskList.addListSelectionListener(e -> displayTaskDetails());
+
+ taskDetails = new JTextArea();
+ taskDetails.setEditable(false);
+
+ acceptButton = new JButton("Accept");
+ rejectButton = new JButton("Reject");
+
+ acceptButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ acceptTask();
+ }
+ });
+
+ rejectButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ rejectTask();
+ }
+ });
+
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.add(acceptButton);
+ buttonPanel.add(rejectButton);
+
+ // Set preferred sizes for the list and detail components
+ taskList.setPreferredSize(new Dimension(200, 150)); // Adjust width and height as needed
+ taskDetails.setPreferredSize(new Dimension(200, 150)); // Adjust width and height as needed
+
+ add(new JScrollPane(taskList), BorderLayout.CENTER);
+ add(new JScrollPane(taskDetails), BorderLayout.SOUTH);
+ add(buttonPanel, BorderLayout.NORTH);
+ }
+
+ public void updateTaskList(List tasks) {
+ System.out.println("add task assignment");
+ for (TaskAssignment task : tasks) {
+ taskListModel.addElement(task);
+ }
+ }
+
+ private void displayTaskDetails() {
+ TaskAssignment selectedTask = taskList.getSelectedValue();
+ if (selectedTask != null) {
+ taskDetails.setText("Name: " + selectedTask.getName() +
+ "\nStatus: " + selectedTask.getStatus() +
+ "\nDue Date: " + selectedTask.getYear() + "-" + selectedTask.getMonth() + "-" + selectedTask.getDay() +
+ "\nContent: " + selectedTask.getContent() +
+ "\nNotification Date: " + selectedTask.getNotificationYear() + "-" + selectedTask.getNotificationMonth() + "-" + selectedTask.getNotificationDay() +
+ "\nAssigned By: " + selectedTask.getTaskAssigner());
+ }
+ }
+
+ private void acceptTask() {
+ TaskAssignment selectedTask = taskList.getSelectedValue();
+ if (selectedTask != null) {
+ Task task = new Task(selectedTask);
+ MainFrame.tasks.add(task);
+ MainFrame.tasksNumber++;
+ MainFrame.refreshMainFrame();
+ taskListModel.removeElement(selectedTask);
+ taskDetails.setText("");
+ }
+ }
+
+ private void rejectTask() {
+ TaskAssignment selectedTask = taskList.getSelectedValue();
+ if (selectedTask != null) {
+ taskListModel.removeElement(selectedTask);
+ taskDetails.setText("");
+ }
+ }
+}
diff --git a/src/client/ChatForm.java b/src/client/ChatForm.java
new file mode 100644
index 0000000..26436d0
--- /dev/null
+++ b/src/client/ChatForm.java
@@ -0,0 +1,37 @@
+package client;
+
+import javax.swing.*;
+import java.awt.BorderLayout;
+import java.awt.event.*;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.Socket;
+import java.io.BufferedReader;
+import java.util.HashMap;
+
+public class ChatForm extends JFrame implements ActionListener {
+ private DataOutputStream serverOut;
+ private ClientInfo info;
+ private HashMap textTable = new HashMap();
+
+ public ChatForm(DataOutputStream serverOut, ClientInfo info) {
+ this.info = info;
+ this.serverOut = serverOut;
+ setupUI();
+ }
+
+
+ public void actionPerformed(ActionEvent e) {
+ this.setVisible(true);
+ }
+
+ private void setupUI() {
+
+ }
+
+ public void updateUI() {
+
+ }
+
+}
diff --git a/src/client/Client.java b/src/client/Client.java
new file mode 100644
index 0000000..8faab14
--- /dev/null
+++ b/src/client/Client.java
@@ -0,0 +1,15 @@
+package client;
+
+public class Client {
+ public static final String SERVER_ADDRESS = "localhost";
+ public static final int SERVER_PORT = 8000;
+ private static ClientInfo info = new ClientInfo();
+
+ public static void main(String[] args) {
+ javax.swing.SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ new LoginForm(info).setVisible(true);
+ }
+ });
+ }
+}
diff --git a/src/client/ClientInfo.java b/src/client/ClientInfo.java
new file mode 100644
index 0000000..bef49dd
--- /dev/null
+++ b/src/client/ClientInfo.java
@@ -0,0 +1,18 @@
+package client;
+
+public class ClientInfo {
+ private String sessionId;
+
+ public ClientInfo() {
+ this.sessionId = null;
+ }
+
+ public String getSessionId() {
+ return this.sessionId;
+ }
+
+ public void setSessionId(String sessionId) {
+ this.sessionId = sessionId;
+ }
+
+}
diff --git a/src/client/ConfirmWindow.java b/src/client/ConfirmWindow.java
new file mode 100644
index 0000000..2f7b1af
--- /dev/null
+++ b/src/client/ConfirmWindow.java
@@ -0,0 +1,54 @@
+package client;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.Socket;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+
+public class ConfirmWindow extends JFrame implements ActionListener{
+ private BufferedReader serverIn;
+ private DataOutputStream serverOut;
+ private ClientInfo info;
+ private Socket socket;
+
+ public ConfirmWindow(DataOutputStream serverOut, BufferedReader serverIn, ClientInfo info, Socket socket) {
+ this.serverIn = serverIn;
+ this.serverOut = serverOut;
+ this.info = info;
+ this.socket = socket;
+
+ setSize(200, 100);
+ setLayout(new BorderLayout());
+ JLabel confirmLabel = new JLabel("Are you sure you want to exit?");
+ add(confirmLabel, BorderLayout.CENTER);
+ JButton exitButton = new JButton("Yes");
+ exitButton.addActionListener(this);
+ add(exitButton, BorderLayout.SOUTH);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ handleExit();
+ System.exit(0);
+ }
+
+ private synchronized void handleExit() {
+ try {
+ serverOut.writeBytes("EXIT " + info.getSessionId() + "\n");
+ System.out.println("Closing connection...");
+ socket.close();
+
+ // Dispose of the frame and exit the application
+ dispose();
+ System.exit(0);
+ } catch (IOException e) {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/client/DateLabelFormatter.java b/src/client/DateLabelFormatter.java
new file mode 100644
index 0000000..2d49c2d
--- /dev/null
+++ b/src/client/DateLabelFormatter.java
@@ -0,0 +1,26 @@
+package client;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import javax.swing.JFormattedTextField.AbstractFormatter;
+
+public class DateLabelFormatter extends AbstractFormatter {
+
+ private String datePattern = "yyyy-MM-dd";
+ private SimpleDateFormat dateFormatter = new SimpleDateFormat(datePattern);
+
+ @Override
+ public Object stringToValue(String text) throws ParseException {
+ return dateFormatter.parseObject(text);
+ }
+
+ @Override
+ public String valueToString(Object value) throws ParseException {
+ if (value != null) {
+ Calendar cal = (Calendar) value;
+ return dateFormatter.format(cal.getTime());
+ }
+ return "";
+ }
+}
diff --git a/src/client/LoginForm.java b/src/client/LoginForm.java
new file mode 100644
index 0000000..a00779f
--- /dev/null
+++ b/src/client/LoginForm.java
@@ -0,0 +1,174 @@
+package client;
+
+import javax.swing.*;
+import java.awt.BorderLayout;
+import java.awt.event.*;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.Socket;
+import java.io.BufferedReader;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+public class LoginForm extends JFrame implements ActionListener {
+ private JTextField usernameField;
+ private JPasswordField passwordField;
+ private JButton loginButton;
+ private JButton registerButton;
+ private JButton exitButton;
+ private JLabel statusLabel;
+ private ClientInfo info;
+ private Socket socket;
+ private BufferedReader serverIn;
+ private DataOutputStream serverOut;
+ private ConfirmWindow confirmWindow;
+
+
+ public LoginForm(ClientInfo info) {
+ this.info = info;
+ setupUI();
+
+ try {
+ this.socket = new Socket(Client.SERVER_ADDRESS, Client.SERVER_PORT);
+ this.serverIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ this.serverOut = new DataOutputStream(socket.getOutputStream());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ confirmWindow = new ConfirmWindow(serverOut, serverIn, info, socket);
+ loginButton.addActionListener(this);
+ registerButton.addActionListener(this);
+ exitButton.addActionListener(this);
+ }
+
+ private void setupUI() {
+ setTitle("Login");
+ setSize(300, 200);
+ setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+ addWindowListener(new CheckOnExit());
+ setLocationRelativeTo(null);
+ setLayout(null);
+
+ JLabel usernameLabel = new JLabel("Username:");
+ usernameLabel.setBounds(10, 30, 80, 25);
+ add(usernameLabel);
+
+ usernameField = new JTextField();
+ usernameField.setBounds(100, 30, 160, 25);
+ add(usernameField);
+
+ JLabel passwordLabel = new JLabel("Password:");
+ passwordLabel.setBounds(10, 70, 80, 25);
+ add(passwordLabel);
+
+ passwordField = new JPasswordField();
+ passwordField.setBounds(100, 70, 160, 25);
+ add(passwordField);
+
+ loginButton = new JButton("Login");
+ loginButton.setBounds(9, 110, 80, 25);
+ add(loginButton);
+
+ registerButton = new JButton("Register");
+ registerButton.setBounds(103, 110, 80, 25);
+ add(registerButton);
+
+ exitButton = new JButton("Exit");
+ exitButton.setBounds(197, 110, 80, 25);
+ add(exitButton);
+
+
+ statusLabel = new JLabel("");
+ statusLabel.setBounds(10, 140, 260, 25);
+ add(statusLabel);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if(e.getSource() == loginButton) {
+ handleLogin();
+ }else if(e.getSource() == exitButton) {
+ this.confirmWindow.setVisible(true);
+ }else if(e.getSource() == registerButton) {
+ new RegistrationForm(serverOut, serverIn).setVisible(true);
+ }
+ }
+
+
+ private synchronized void handleLogin() {
+ String username = usernameField.getText();
+ String password = new String(passwordField.getPassword());
+
+ try {
+ serverOut.writeBytes("LOGIN " + username + " " + password + "\n");
+
+ String response = serverIn.readLine();
+ statusLabel.setText("Server response: " + response);
+
+ if (response.startsWith("Login Successfully!")) {
+ // Schedule session refresh task
+ String sessionId = response.split(" ")[2];
+ info.setSessionId(sessionId);
+
+ if(info.getSessionId() != null) {
+ ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+ scheduler.scheduleAtFixedRate(new Runnable() {
+ @Override
+ public void run() {
+ sendSessionRefresh(serverOut);
+ }
+ }, 0, 28, TimeUnit.MINUTES);
+ }
+
+
+ statusLabel.setText("Login successful");
+ // Hide the login form and proceed to task management
+ usernameField.setText("");
+ passwordField.setText("");
+ usernameField.requestFocus();
+ setVisible(false);
+
+ new MainFrame(serverOut, serverIn, info, confirmWindow, this);
+ } else {
+ statusLabel.setText("Login failed: " + response.split(": ")[1]);
+ // Clear the text fields and focus on username field
+ usernameField.setText("");
+ passwordField.setText("");
+ usernameField.requestFocus();
+ }
+ } catch (IOException e) {
+ statusLabel.setText("Error: " + e.getMessage());
+ // Clear the text fields and focus on username field
+ usernameField.setText("");
+ passwordField.setText("");
+ usernameField.requestFocus();
+ }
+ }
+
+
+ private class CheckOnExit implements WindowListener{
+ public void windowClosing(WindowEvent e) {
+ confirmWindow.setVisible(true);
+ }
+
+ public void windowOpened(WindowEvent e) {}
+ public void windowClosed(WindowEvent e) {}
+ public void windowIconified(WindowEvent e) {}
+ public void windowDeiconified(WindowEvent e) {}
+ public void windowActivated(WindowEvent e) {}
+ public void windowDeactivated(WindowEvent e) {}
+
+ }
+
+
+ private synchronized void sendSessionRefresh(DataOutputStream serverOut) {
+ try {
+ serverOut.writeBytes("SESSION_REFRESH " + info.getSessionId() + "\n");
+ System.out.println("Session refreshed.");
+ } catch (IOException e) {
+ System.out.println("Error refreshing session: " + e.getMessage());
+ }
+ }
+}
diff --git a/src/client/MainFrame.java b/src/client/MainFrame.java
new file mode 100644
index 0000000..76a86c5
--- /dev/null
+++ b/src/client/MainFrame.java
@@ -0,0 +1,368 @@
+package client;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Dimension;
+import org.jdatepicker.impl.JDatePanelImpl;
+import org.jdatepicker.impl.JDatePickerImpl;
+import org.jdatepicker.impl.UtilDateModel;
+
+import javax.swing.*;
+import java.util.Properties;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import parameter.*;
+
+public class MainFrame {
+ public static List tasks = new ArrayList<>();
+ public static int tasksNumber = 0; // 目前的 task 數量
+ private static Container cp;
+ private static JFrame frame;
+ private static JPanel taskPanel;
+ private BufferedReader serverIn;
+ private static DataOutputStream serverOut;
+ private static ClientInfo info;
+ private ChatForm chatForm;
+ private JButton chatSystem;
+ private static ServerResponse serverResponse;
+ private ConfirmWindow confirmWindow;
+ private LoginForm loginForm;
+ private AssignBox assignBox;
+
+ public MainFrame(DataOutputStream serverOut, BufferedReader serverIn, ClientInfo info, ConfirmWindow confirmWindow, LoginForm loginForm) {
+ this.info = info;
+ this.serverIn = serverIn;
+ this.serverOut = serverOut;
+ this.confirmWindow = confirmWindow;
+ this.loginForm = loginForm;
+ chatForm = new ChatForm(serverOut, info);
+ createMainFrame();
+ // open server message listener
+ serverResponse = new ServerResponse();
+ serverResponse.setVisible(true);
+ this.assignBox = new AssignBox();
+ new Thread(new MessageHandler(serverIn, this.serverResponse, this.frame, this.loginForm, this.assignBox)).start();
+ //send data request to server...
+ initRequest();
+
+ // register listener
+ chatSystem.addActionListener(chatForm);
+ }
+
+ private void createMainFrame() {
+ // 介面建立
+ frame = new JFrame();
+ frame.setSize(1200, 600);
+ frame.setLocation(100, 150);
+ frame.setTitle("Demo");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+ MainFrame.cp = frame.getContentPane();
+ MainFrame.cp.setLayout(null);
+
+ // Scrollable task panel
+ taskPanel = new JPanel();
+ taskPanel.setLayout(new BoxLayout(taskPanel, BoxLayout.Y_AXIS)); // Use BoxLayout for dynamic content
+
+
+ // Create a JScrollPane to contain the task panel
+ JScrollPane scrollPane = new JScrollPane(taskPanel);
+ scrollPane.setBounds(20, 60, 930, 480); // Adjust size and position as needed
+ scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+ scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); // Disable horizontal scroll
+ cp.add(scrollPane);
+
+
+ // 照狀態排序
+ JButton sortByStatusButton = new JButton("Sort by Status");
+ sortByStatusButton.setBounds(970, 20, 150, 25);
+ sortByStatusButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ TaskTracking.sortByStatus();
+ for (int i = 0; i < 3; i++) {
+ System.out.println(MainFrame.tasks.get(i).getUserIDs());
+ }
+ refreshMainFrame();
+ }
+ });
+ cp.add(sortByStatusButton);
+
+ // 照日期排序
+ JButton sortByDateButton = new JButton("Sort by Date");
+ sortByDateButton.setBounds(970, 55, 150, 25);
+ sortByDateButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ TaskTracking.sortByDate();
+ for (int i = 0; i < 3; i++) {
+ System.out.println(MainFrame.tasks.get(i).getUserIDs());
+ }
+ refreshMainFrame();
+ }
+ });
+ cp.add(sortByDateButton);
+
+ JButton createButton = new JButton("Create");
+ createButton.setBounds(970, 90, 150, 25);
+ createButton.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ TaskManagement.Create(frame);
+ refreshMainFrame();
+ }
+ });
+ cp.add(createButton);
+
+ // Assign Box button
+ JButton assignBoxButton = new JButton("Assign Box");
+ assignBoxButton.setBounds(970, 125, 150, 25);
+ assignBoxButton.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ assignBox.setVisible(true);
+ }
+ });
+ cp.add(assignBoxButton);
+
+ // Save button
+ JButton SaveButton = new JButton("Save");
+ SaveButton.setBounds(970, 160, 150, 25);
+ SaveButton.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ updateTask(serverOut, tasks);
+ }
+ });
+ cp.add(SaveButton);
+
+ // Logout button
+ JButton LogoutButton = new JButton("Logout");
+ LogoutButton.setBounds(970, 195, 150, 25);
+ LogoutButton.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ logout(serverOut, info);
+ }
+ });
+ cp.add(LogoutButton);
+
+ // EXIT button
+ JButton ExitButton = new JButton("EXIT");
+ ExitButton.setBounds(970, 230, 150, 25);
+ ExitButton.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ confirmWindow.setVisible(true);
+ }
+ });
+ cp.add(ExitButton);
+
+
+ frame.setVisible(true);
+ }
+
+ public static void refreshMainFrame() {
+ taskPanel.removeAll();
+
+ // Add labels row
+ JPanel labelPanel = new JPanel();
+ labelPanel.setPreferredSize(new Dimension(800, 24));
+ labelPanel.setMaximumSize(new Dimension(800, 24));
+ labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.X_AXIS));
+
+ // Add empty label for "-" column
+ labelPanel.add(Box.createRigidArea(new Dimension(50, 24)));
+
+ // Add labels
+ JLabel names = new JLabel("Task Names");
+ names.setPreferredSize(new Dimension(150, 24));
+ names.setMaximumSize(new Dimension(150, 24));
+ names.setHorizontalAlignment(SwingConstants.LEADING); // Center align text
+ labelPanel.add(names);
+
+ JLabel status = new JLabel("Status");
+ status.setPreferredSize(new Dimension(150, 24));
+ status.setMaximumSize(new Dimension(150, 24));
+ status.setHorizontalAlignment(SwingConstants.LEADING); // Center align text
+ labelPanel.add(status);
+
+ JLabel date = new JLabel("Dead Line");
+ date.setPreferredSize(new Dimension(200, 24));
+ date.setMaximumSize(new Dimension(200, 24));
+ date.setHorizontalAlignment(SwingConstants.LEADING); // Center align text
+ labelPanel.add(date);
+
+ taskPanel.add(labelPanel);
+
+ // Add tasks to panel
+ for (int i = 0; i < tasksNumber; i++) {
+ final int finalI = i;
+ JPanel tp = new JPanel();
+ tp.setPreferredSize(new Dimension(800, 35));
+ tp.setMaximumSize(new Dimension(800, 35));
+ tp.setLayout(new BoxLayout(tp, BoxLayout.X_AXIS));
+
+ // Delete task button
+ JButton deleteButton = new JButton("-");
+ deleteButton.setPreferredSize(new Dimension(50, 30));
+ deleteButton.setMaximumSize(new Dimension(50, 30));
+ deleteButton.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ TaskManagement.Delete(finalI, frame);
+ refreshMainFrame();
+ }
+ });
+ tp.add(deleteButton);
+
+ // Task name button
+ JButton button = new JButton(tasks.get(i).getName());
+ button.setPreferredSize(new Dimension(150, 30));
+ button.setMaximumSize(new Dimension(150, 30));
+ button.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ TaskManagement.Edit(finalI);
+ refreshMainFrame();
+ }
+ });
+ tp.add(button);
+
+ // Task status combo box
+ String[] choices = {"Done", "In Progress", "Not Started"};
+ final JComboBox comboBox = new JComboBox<>(choices);
+ comboBox.setPreferredSize(new Dimension(150, 30));
+ comboBox.setMaximumSize(new Dimension(150, 30));
+ comboBox.setSelectedItem(tasks.get(i).getStatus());
+ comboBox.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ if (e.getStateChange() == ItemEvent.SELECTED) {
+ String selectedOption = (String) comboBox.getSelectedItem();
+ tasks.get(finalI).setStatus(selectedOption);
+ }
+ }
+ });
+ tp.add(comboBox);
+
+ // Task date picker
+ UtilDateModel model = new UtilDateModel();
+ Calendar defaultDate = Calendar.getInstance();
+ defaultDate.set(tasks.get(i).getYear(), tasks.get(i).getMonth() - 1, tasks.get(i).getDay());
+ model.setValue(defaultDate.getTime());
+
+ Properties p = new Properties();
+ p.put("text.today", "Today");
+ p.put("text.month", "Month");
+ p.put("text.year", "Year");
+ JDatePanelImpl datePanel = new JDatePanelImpl(model, p);
+ final JDatePickerImpl datePicker = new JDatePickerImpl(datePanel, new DateLabelFormatter());
+ datePicker.setPreferredSize(new Dimension(200, 30));
+ datePicker.setMaximumSize(new Dimension(200, 30));
+ datePicker.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Date selectedDate = (Date) datePicker.getModel().getValue();
+ if (selectedDate != null) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(selectedDate);
+ tasks.get(finalI).setYear(cal.get(Calendar.YEAR));
+ tasks.get(finalI).setMonth(cal.get(Calendar.MONTH) + 1);
+ tasks.get(finalI).setDay(cal.get(Calendar.DAY_OF_MONTH));
+ }
+ }
+ });
+
+ JPanel panel = new JPanel();
+ panel.setPreferredSize(new Dimension(200, 30));
+ panel.setMaximumSize(new Dimension(200, 30));
+ panel.add(datePicker);
+ tp.add(panel);
+
+ // Task assign button
+ JButton buttonAssign = new JButton("Assign");
+ buttonAssign.setPreferredSize(new Dimension(150, 30));
+ buttonAssign.setMaximumSize(new Dimension(150, 30));
+ buttonAssign.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ TaskManagement.Assigns(serverResponse, info, serverOut, tasks.get(finalI), finalI);
+ refreshMainFrame();
+ }
+ });
+ tp.add(buttonAssign);
+
+ // Notification 按鈕的驚嘆號(作為通知用)
+ JLabel notificationLabel = new JLabel("!");
+ notificationLabel.setPreferredSize(new Dimension(50, 30));
+ notificationLabel.setMaximumSize(new Dimension(50, 30));
+ notificationLabel.setVisible(false);
+ notificationLabel.setForeground(Color.RED);
+ tp.add(notificationLabel);
+
+ // 判定當天是否有通知
+ boolean hasNotificationToday = false;
+ Calendar today = Calendar.getInstance();
+ today.set(Calendar.HOUR_OF_DAY, 0);
+ today.set(Calendar.MINUTE, 0);
+ today.set(Calendar.SECOND, 0);
+ today.set(Calendar.MILLISECOND, 0);
+
+ for (Task task : tasks) {
+ if (task.getNotificationYear() == today.get(Calendar.YEAR) &&
+ task.getNotificationMonth() == today.get(Calendar.MONTH) + 1 &&
+ task.getNotificationDay() == today.get(Calendar.DAY_OF_MONTH)) {
+ hasNotificationToday = true;
+ break;
+ }
+ }
+
+ // 有通知就顯現驚嘆號
+ if (hasNotificationToday) {
+ notificationLabel.setVisible(true);
+ }
+
+
+ taskPanel.add(tp);
+ }
+
+ taskPanel.revalidate();
+ taskPanel.repaint();
+ }
+
+
+ private synchronized void initRequest() {
+ try {
+ serverOut.writeBytes("USER_INIT_DATA" + " " + info.getSessionId() + "\n");
+ }catch(IOException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ private static synchronized void logout(DataOutputStream serverOut, ClientInfo info){
+ serverResponse.init();
+ serverResponse.setVisible(true);
+ try {
+ serverOut.writeBytes("LOGOUT" + " " + info.getSessionId() + "\n");
+ info.setSessionId(null);
+ }catch(IOException e) {
+
+ }
+ }
+
+ private static synchronized void updateTask(DataOutputStream serverOut, List tasks){
+ serverResponse.init();
+ serverResponse.setVisible(true);
+ try {
+ StringBuilder taskDataBuilder = new StringBuilder();
+ for(Task task : tasks) {
+ String taskData = task.toString();
+ taskDataBuilder.append(taskData).append(";");
+ }
+ serverOut.writeBytes("UPDATE_TASK" + " " + info.getSessionId() + " " + taskDataBuilder.toString() + "\n");
+ }catch(IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+}
diff --git a/src/client/MessageHandler.java b/src/client/MessageHandler.java
new file mode 100644
index 0000000..79b797b
--- /dev/null
+++ b/src/client/MessageHandler.java
@@ -0,0 +1,175 @@
+package client;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.StringTokenizer;
+import javax.swing.JFrame;
+import parameter.ServerInMsg;
+import task.TaskAssignment;
+
+public class MessageHandler implements Runnable {
+ private BufferedReader serverIn;
+ private ServerResponse serverResponse;
+ private JFrame frame;
+ private JFrame loginForm;
+ private AssignBox assignBox;
+ private volatile boolean running = true; // Add a flag to control the loop
+
+ public MessageHandler(BufferedReader serverIn, ServerResponse serverResponse, JFrame frame, JFrame loginForm, AssignBox assignBox) {
+ this.serverIn = serverIn;
+ this.serverResponse = serverResponse;
+ this.frame = frame;
+ this.loginForm = loginForm;
+ this.assignBox = assignBox;
+ }
+
+ @Override
+ public void run() {
+ try {
+ String message;
+ while (running && (message = serverIn.readLine()) != null) {
+ System.out.println("received server response :" + message);
+ processMessage(message);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void processMessage(String message) {
+ StringTokenizer tokenizer = new StringTokenizer(message);
+ String commandType = tokenizer.nextToken();
+
+ switch (ServerInMsg.getEnum(commandType)) {
+ case RE_UPDATE_TASK:
+ handleUpdateReply(tokenizer);
+ break;
+ case RE_ASSIGN:
+ handleAssignReply(tokenizer);
+ break;
+ case RE_LOGOUT:
+ handleLogout(tokenizer);
+ break;
+ case INIT_TASK:
+ handleInit(tokenizer);
+ break;
+ case UPDATE_TASK:
+ handleTaskUpdate(tokenizer);
+ // handle task update
+ break;
+ case INIT_CHAT:
+ break;
+ case UPDATE_CHAT:
+ // handle chat update
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void handleInit(StringTokenizer tokenizer) {
+ if (tokenizer.countTokens() < 1) {
+ serverResponse.show("Invalid Command");
+ return;
+ }
+
+ String status = tokenizer.nextToken();
+ if (status.equals("SUCCESS")) {
+ serverResponse.show("request initial data:" + status);
+ } else {
+ serverResponse.show(status + tokenizer.nextToken());
+ }
+
+
+
+ List tasks = new ArrayList<>();
+ while (tokenizer.hasMoreTokens()) {
+ String taskData = tokenizer.nextToken(";");
+ String[] fields = taskData.split("\\|");
+ Task task = new Task(
+ fields[0], // name
+ fields[1], // status
+ Integer.parseInt(fields[2]), // year
+ Integer.parseInt(fields[3]), // month
+ Integer.parseInt(fields[4]), // day
+ fields[5], // content
+ Integer.parseInt(fields[6]), // notificationYear
+ Integer.parseInt(fields[7]), // notificationMonth
+ Integer.parseInt(fields[8]) // notificationDay
+ );
+ if(fields.length > 9 && fields[9] != null) {
+ task.setUserIDs(new ArrayList<>(Arrays.asList(fields[9].split(","))));
+ }
+ MainFrame.tasks.add(task);
+ }
+
+ MainFrame.tasksNumber = MainFrame.tasks.size();
+ MainFrame.refreshMainFrame();
+ }
+
+ private void handleUpdateReply(StringTokenizer tokenizer) {
+ String status = tokenizer.nextToken();
+ if (status.equals("SUCCESS")) {
+ serverResponse.show("data are sucessfully update to database !\n");
+ } else if (status.equals("FAIL")) {
+ serverResponse.show("data are faild to update to database !\n");
+ } else {
+ serverResponse.show("session is invalid, please relogin....\n");
+ }
+ }
+
+ private void handleAssignReply(StringTokenizer tokenizer) {
+ String status = tokenizer.nextToken();
+ if (status.equals("SUCCESS")) {
+ serverResponse.show("task assign process success\n");
+ } else if (status.equals("FAIL")) {
+ if(tokenizer.hasMoreTokens()) {
+ serverResponse.show("task assign process fail " + tokenizer.nextToken("\n"));
+ }else {
+ serverResponse.show("task assign process fail\n");
+ }
+ } else {
+ serverResponse.show("session is invalid, please relogin....\n");
+ }
+ }
+
+ private void handleLogout(StringTokenizer tokenizer) {
+ String status = tokenizer.nextToken();
+ System.out.println(status);
+ if (status.equals("SUCCESS")) {
+ serverResponse.show("Logout successfully: go back to login interface...");
+ MainFrame.tasks.clear();
+ frame.getContentPane().removeAll();
+ frame.dispose();
+ loginForm.setVisible(true);
+ running = false; // Call to stop the thread
+ } else {
+ serverResponse.show("Invalid Request");
+ }
+ }
+
+ private void handleTaskUpdate(StringTokenizer tokenizer) {
+ List taskAssignments = new ArrayList<>();
+ while(tokenizer.hasMoreTokens()) {
+ String taskInfo = tokenizer.nextToken(";");
+ String[] fields = taskInfo.split("\\|");
+ TaskAssignment task = new TaskAssignment(fields[0], // name
+ fields[1], // status
+ Integer.parseInt(fields[2]), // year
+ Integer.parseInt(fields[3]), // month
+ Integer.parseInt(fields[4]), // day
+ fields[5], // content
+ Integer.parseInt(fields[6]), // notificationYear
+ Integer.parseInt(fields[7]), // notificationMonth
+ Integer.parseInt(fields[8]), // notificationDay)
+ fields[9]);
+ taskAssignments.add(task);
+ }
+ assignBox.updateTaskList(taskAssignments);
+ serverResponse.show("There's new assignment, check out Assign Box !");
+ }
+
+}
diff --git a/src/client/Notification.java b/src/client/Notification.java
new file mode 100644
index 0000000..3f8e9f9
--- /dev/null
+++ b/src/client/Notification.java
@@ -0,0 +1,97 @@
+package client;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableModel;
+import java.awt.*;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+public class Notification {
+
+ public static void notification() {
+ JFrame frame = new JFrame("Notifications");
+ frame.setSize(800, 400);
+ frame.setLocationRelativeTo(null);
+ frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+
+ JPanel panel = new JPanel(new BorderLayout());
+
+
+ JTable table = new JTable();
+ DefaultTableModel model = new DefaultTableModel(new Object[]{"Name", "Status", "Task Date", "Content", "Notification Date"}, 0);
+ table.setModel(model);
+
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ Calendar today = Calendar.getInstance();
+ today.set(Calendar.HOUR_OF_DAY, 0);
+ today.set(Calendar.MINUTE, 0);
+ today.set(Calendar.SECOND, 0);
+ today.set(Calendar.MILLISECOND, 0);
+
+ List notifications = new ArrayList<>();
+
+ for (Task task : MainFrame.tasks) {
+ if (task.getNotificationYear() != 0 && task.getNotificationMonth() != 0 && task.getNotificationDay() != 0) {
+ Calendar notificationDate = Calendar.getInstance();
+ notificationDate.set(task.getNotificationYear(), task.getNotificationMonth() - 1, task.getNotificationDay());
+ notificationDate.set(Calendar.HOUR_OF_DAY, 0);
+ notificationDate.set(Calendar.MINUTE, 0);
+ notificationDate.set(Calendar.SECOND, 0);
+ notificationDate.set(Calendar.MILLISECOND, 0);
+
+ if (!notificationDate.after(today)) {
+ notifications.add(task);
+ }
+ }
+ }
+
+
+ Collections.sort(notifications, (t1, t2) -> {
+ Calendar date1 = Calendar.getInstance();
+ date1.set(t1.getNotificationYear(), t1.getNotificationMonth() - 1, t1.getNotificationDay());
+
+ Calendar date2 = Calendar.getInstance();
+ date2.set(t2.getNotificationYear(), t2.getNotificationMonth() - 1, t2.getNotificationDay());
+
+ return date1.compareTo(date2);
+ });
+
+ for (Task task : notifications) {
+
+ Calendar taskDate = Calendar.getInstance();
+ taskDate.set(task.getYear(), task.getMonth() - 1, task.getDay());
+ taskDate.set(Calendar.HOUR_OF_DAY, 0);
+ taskDate.set(Calendar.MINUTE, 0);
+ taskDate.set(Calendar.SECOND, 0);
+ taskDate.set(Calendar.MILLISECOND, 0);
+
+
+ model.addRow(new Object[]{task.getName(), task.getStatus(), sdf.format(convertToDate(taskDate)), task.getContent(), sdf.format(convertToDate(task.getNotificationYear(), task.getNotificationMonth(), task.getNotificationDay()))});
+ }
+
+
+ JScrollPane scrollPane = new JScrollPane(table);
+ panel.add(scrollPane, BorderLayout.CENTER);
+
+
+ frame.add(panel);
+ frame.setVisible(true);
+ }
+
+
+ private static Date convertToDate(Calendar calendar) {
+ return calendar.getTime();
+ }
+
+
+ private static Date convertToDate(int year, int month, int day) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.set(year, month - 1, day, 0, 0, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ return calendar.getTime();
+ }
+}
diff --git a/src/client/RegistrationForm.java b/src/client/RegistrationForm.java
new file mode 100644
index 0000000..6833a2e
--- /dev/null
+++ b/src/client/RegistrationForm.java
@@ -0,0 +1,91 @@
+package client;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class RegistrationForm extends JFrame {
+ private JTextField usernameField;
+ private JPasswordField passwordField;
+ private JButton registerButton;
+ private JLabel statusLabel;
+ private DataOutputStream serverOut;
+ private BufferedReader serverIn;
+
+ public RegistrationForm(DataOutputStream serverOut, BufferedReader serverIn) {
+ this.serverOut = serverOut;
+ this.serverIn = serverIn;
+ setupUI();
+ }
+
+ private void setupUI() {
+ setTitle("Registration");
+ setSize(300, 200);
+ setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+ setLocationRelativeTo(null);
+ setLayout(null);
+
+ JLabel usernameLabel = new JLabel("Username:");
+ usernameLabel.setBounds(10, 30, 80, 25);
+ add(usernameLabel);
+
+ usernameField = new JTextField();
+ usernameField.setBounds(100, 30, 160, 25);
+ add(usernameField);
+
+ JLabel passwordLabel = new JLabel("Password:");
+ passwordLabel.setBounds(10, 70, 80, 25);
+ add(passwordLabel);
+
+ passwordField = new JPasswordField();
+ passwordField.setBounds(100, 70, 160, 25);
+ add(passwordField);
+
+ registerButton = new JButton("Register");
+ registerButton.setBounds(10, 110, 80, 25);
+ add(registerButton);
+
+ statusLabel = new JLabel("");
+ statusLabel.setBounds(10, 140, 260, 25);
+ add(statusLabel);
+
+ registerButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ handleRegistration();
+ }
+ });
+ }
+
+ private void handleRegistration() {
+ String username = usernameField.getText();
+ String password = new String(passwordField.getPassword());
+
+ try {
+ serverOut.writeBytes("REGISTRATION " + username + " " + password + "\n");
+
+ String response = serverIn.readLine();
+ statusLabel.setText("Server response: " + response);
+
+ if (response.startsWith("Registeration Sucessed")) {
+ statusLabel.setText("Registration successful");
+
+ dispose();
+ } else {
+ statusLabel.setText(response);
+ usernameField.setText("");
+ passwordField.setText("");
+ usernameField.requestFocus();
+ }
+ } catch (IOException e) {
+ statusLabel.setText("Error: " + e.getMessage());
+ // Clear the text fields and focus on username field
+ usernameField.setText("");
+ passwordField.setText("");
+ usernameField.requestFocus();
+ }
+ }
+}
diff --git a/src/client/ServerResponse.java b/src/client/ServerResponse.java
new file mode 100644
index 0000000..bdf51a1
--- /dev/null
+++ b/src/client/ServerResponse.java
@@ -0,0 +1,38 @@
+package client;
+
+import java.awt.BorderLayout;
+
+import javax.swing.*;
+
+public class ServerResponse extends JFrame {
+ private JLabel status;
+
+ public ServerResponse(){
+ setSize(400, 200);
+ setLocationRelativeTo(null);
+ setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+ setLayout(new BorderLayout());
+
+ status = new JLabel("wait for server response....", SwingConstants.CENTER);
+ add(status, BorderLayout.CENTER);
+ }
+
+ public void init() {
+ status.setText("wait for server response....");
+ }
+
+ public void show(String response) {
+ this.setVisible(true);
+ status.setText(response);
+
+ try {
+ Thread.sleep(1500);
+ }catch(InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ this.setVisible(false);
+
+ }
+
+}
diff --git a/src/client/Task.java b/src/client/Task.java
new file mode 100644
index 0000000..a1cb544
--- /dev/null
+++ b/src/client/Task.java
@@ -0,0 +1,186 @@
+package client;
+
+import java.util.ArrayList;
+import task.TaskAssignment;
+
+public class Task {
+ private String name;
+ private String status;
+ private int year;
+ private int month;
+ private int day;
+ private String content;
+ private ArrayList userIDs;
+ private int notificationYear;
+ private int notificationMonth;
+ private int notificationDay;
+
+ public Task(String name, String status, int year, int month, int day, String content) {
+ this.name = name;
+ this.status = status;
+ this.year = year;
+ this.month = month;
+ this.day = day;
+ this.content = content;
+ this.notificationYear = 0;
+ this.notificationMonth = 0;
+ this.notificationDay = 0;
+ this.userIDs = new ArrayList<>();
+ }
+
+ public Task(String name, String status, int year, int month, int day, String content, int notificationYear, int notificationMonth, int notificationDay) {
+ this.name = name;
+ this.status = status;
+ this.year = year;
+ this.month = month;
+ this.day = day;
+ this.content = content;
+ this.notificationYear = notificationYear;
+ this.notificationMonth = notificationMonth;
+ this.notificationDay = notificationDay;
+ this.userIDs = new ArrayList<>();
+ }
+
+ public Task(String name, String status, int year, int month, int day, String content, int notificationYear, int notificationMonth, int notificationDay, ArrayList userIds) {
+ this.name = name;
+ this.status = status;
+ this.year = year;
+ this.month = month;
+ this.day = day;
+ this.content = content;
+ this.notificationYear = notificationYear;
+ this.notificationMonth = notificationMonth;
+ this.notificationDay = notificationDay;
+ this.userIDs = userIds;
+ }
+
+ public Task(TaskAssignment taskAssignment) {
+ this.name = taskAssignment.getName();
+ this.status = taskAssignment.getStatus();
+ this.year = taskAssignment.getYear();
+ this.month = taskAssignment.getMonth();
+ this.day = taskAssignment.getDay();
+ this.content = taskAssignment.getContent();
+ this.notificationYear = taskAssignment.getNotificationYear();
+ this.notificationMonth = taskAssignment.getNotificationMonth();
+ this.notificationDay = taskAssignment.getNotificationDay();
+ this.userIDs = new ArrayList<>();
+ }
+
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public int getYear() {
+ return year;
+ }
+
+ public void setYear(int year) {
+ this.year = year;
+ }
+
+ public int getMonth() {
+ return month;
+ }
+
+ public void setMonth(int month) {
+ this.month = month;
+ }
+
+ public int getDay() {
+ return day;
+ }
+
+ public void setDay(int day) {
+ this.day = day;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public ArrayList getUserIDs() {
+ return userIDs;
+ }
+
+ public void setUserIDs(ArrayList userIDs) {
+ this.userIDs = userIDs;
+ }
+
+ public void addUser(String userID) {
+ userIDs.add(userID);
+ }
+
+ public void removeUser(String userID) {
+ userIDs.remove(userID);
+ }
+
+ public int getNotificationYear() {
+ return notificationYear;
+ }
+
+ public void setNotificationYear(int notificationYear) {
+ this.notificationYear = notificationYear;
+ }
+
+ public int getNotificationMonth() {
+ return notificationMonth;
+ }
+
+ public void setNotificationMonth(int notificationMonth) {
+ this.notificationMonth = notificationMonth;
+ }
+
+ public int getNotificationDay() {
+ return notificationDay;
+ }
+
+ public void setNotificationDay(int notificationDay) {
+ this.notificationDay = notificationDay;
+ }
+
+ public String toString() {
+ String taskData = this.getName() + "|" +
+ this.getStatus() + "|" +
+ this.getYear() + "|" +
+ this.getMonth() + "|" +
+ this.getDay() + "|" +
+ this.getContent() + "|" +
+ this.getNotificationYear() + "|" +
+ this.getNotificationMonth() + "|" +
+ this.getNotificationDay() + "|" +
+ String.join(",", this.getUserIDs());
+ return taskData;
+ }
+
+ public String toAssignString(String assignedUser) {
+ String taskData = this.getName() + "|" +
+ this.getStatus() + "|" +
+ this.getYear() + "|" +
+ this.getMonth() + "|" +
+ this.getDay() + "|" +
+ this.getContent() + "|" +
+ this.getNotificationYear() + "|" +
+ this.getNotificationMonth() + "|" +
+ this.getNotificationDay() + "|" +
+ assignedUser;
+ return taskData;
+ }
+}
diff --git a/src/client/TaskManagement.java b/src/client/TaskManagement.java
new file mode 100644
index 0000000..8a186a8
--- /dev/null
+++ b/src/client/TaskManagement.java
@@ -0,0 +1,224 @@
+package client;
+
+import javax.swing.JFrame;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.JTextArea;
+
+import org.jdatepicker.impl.JDatePanelImpl;
+import org.jdatepicker.impl.JDatePickerImpl;
+import org.jdatepicker.impl.UtilDateModel;
+
+import javax.swing.JComboBox;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+import java.awt.Container;
+import java.util.Calendar;
+import java.util.Date;
+
+
+public class TaskManagement {
+
+ private static Container cp;
+
+ public static void Create(JFrame frame) { // index 為當下所按的"+"的是第幾個tasks
+
+ MainFrame.tasksNumber++; // Increase the task count
+ // 預設日期為創建task的當天日期
+ Calendar calendar = Calendar.getInstance();
+ int year = calendar.get(Calendar.YEAR);
+ int month = calendar.get(Calendar.MONTH) + 1;
+ int day = calendar.get(Calendar.DAY_OF_MONTH);
+
+ MainFrame.tasks.add(0, new Task("New Task", "Not Started", year, month, day, ""));
+
+ frame.revalidate();
+ frame.repaint();
+ }
+
+ public static void Delete(int index, JFrame frame) { // 刪掉目前的task
+ // 刪除指定的task
+ MainFrame.tasks.remove(index);
+ MainFrame.tasksNumber--; // 總數量減少
+ frame.revalidate();
+ frame.repaint();
+ }
+
+ public static void Edit(int index) {
+ JFrame frame = new JFrame();
+ frame.setSize(500, 500);
+ frame.setLocation(100, 150);
+ frame.setTitle("Edit");
+ frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+
+ cp = frame.getContentPane();
+ cp.setLayout(null);
+
+ // task的name標籤
+ JLabel nameLabel = new JLabel("Task Name:");
+ nameLabel.setBounds(20, 20, 100, 25);
+ cp.add(nameLabel);
+
+ // task的name資料(更改地方)
+ JTextField nameTextField = new JTextField(MainFrame.tasks.get(index).getName());
+ nameTextField.setBounds(130, 20, 200, 25);
+ cp.add(nameTextField);
+
+ // task的status標籤
+ JLabel statusLabel = new JLabel("Status:");
+ statusLabel.setBounds(20, 60, 100, 25);
+ cp.add(statusLabel);
+
+ // task的status資料(更改地方)
+ String[] statusOptions = {"Done", "In Progress", "Not Started"};
+ JComboBox statusComboBox = new JComboBox<>(statusOptions);
+ statusComboBox.setSelectedItem(MainFrame.tasks.get(index).getStatus());
+ statusComboBox.setBounds(130, 60, 200, 25);
+ cp.add(statusComboBox);
+
+ // task的date標籤
+ JLabel dateLabel = new JLabel("Date:");
+ dateLabel.setBounds(20, 100, 100, 25);
+ cp.add(dateLabel);
+
+ // task的date資料(更改地方)
+ UtilDateModel model = new UtilDateModel();
+ if (MainFrame.tasks.get(index).getYear() != 0 && MainFrame.tasks.get(index).getMonth() != 0 && MainFrame.tasks.get(index).getDay() != 0) {
+ Calendar defaultDate = Calendar.getInstance();
+ defaultDate.set(MainFrame.tasks.get(index).getYear(), MainFrame.tasks.get(index).getMonth() - 1, MainFrame.tasks.get(index).getDay()); // 設置預設日期
+ model.setValue(defaultDate.getTime());
+ }
+ Properties p = new Properties();
+ p.put("text.today", "Today");
+ p.put("text.month", "Month");
+ p.put("text.year", "Year");
+ JDatePanelImpl datePanel = new JDatePanelImpl(model, p);
+ JDatePickerImpl datePicker = new JDatePickerImpl(datePanel, new DateLabelFormatter());
+ JPanel datePanelContainer = new JPanel();
+ datePanelContainer.add(datePicker);
+ datePanelContainer.setBounds(130, 100, 200, 30);
+ cp.add(datePanelContainer);
+
+ // task的notification標籤
+ JLabel notificationLabel = new JLabel("Notification:");
+ notificationLabel.setBounds(20, 140, 100, 25);
+ cp.add(notificationLabel);
+
+ // task的notification資料(更改地方)
+ UtilDateModel notificationModel = new UtilDateModel();
+ if (MainFrame.tasks.get(index).getNotificationYear() != 0 && MainFrame.tasks.get(index).getNotificationMonth() != 0 && MainFrame.tasks.get(index).getNotificationDay() != 0) {
+ Calendar defaultNotification = Calendar.getInstance();
+ defaultNotification.set(MainFrame.tasks.get(index).getNotificationYear(), MainFrame.tasks.get(index).getNotificationMonth() - 1, MainFrame.tasks.get(index).getNotificationDay()); // 設置預設notification日期
+ notificationModel.setValue(defaultNotification.getTime());
+ }
+ JDatePanelImpl notificationDatePanel = new JDatePanelImpl(notificationModel, p);
+ JDatePickerImpl notificationDatePicker = new JDatePickerImpl(notificationDatePanel, new DateLabelFormatter());
+ JPanel notificationPanelContainer = new JPanel();
+ notificationPanelContainer.add(notificationDatePicker);
+ notificationPanelContainer.setBounds(130, 140, 200, 30);
+ cp.add(notificationPanelContainer);
+
+ // task的內容標籤
+ JLabel contentLabel = new JLabel("Content:");
+ contentLabel.setBounds(20, 180, 100, 25);
+ cp.add(contentLabel);
+
+ // task的內容資料(更改地方)
+ JTextArea contentTextArea = new JTextArea(MainFrame.tasks.get(index).getContent());
+ contentTextArea.setBounds(130, 180, 200, 100);
+ cp.add(contentTextArea);
+
+ // 儲存
+ JButton saveButton = new JButton("Save");
+ saveButton.setBounds(100, 300, 100, 25);
+ saveButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ MainFrame.tasks.get(index).setName(nameTextField.getText());
+ MainFrame.tasks.get(index).setStatus((String) statusComboBox.getSelectedItem());
+ Date selectedDate = (Date) datePicker.getModel().getValue();
+ if (selectedDate != null) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(selectedDate);
+ MainFrame.tasks.get(index).setYear(cal.get(Calendar.YEAR));
+ MainFrame.tasks.get(index).setMonth(cal.get(Calendar.MONTH) + 1);
+ MainFrame.tasks.get(index).setDay(cal.get(Calendar.DAY_OF_MONTH));
+ }
+ Date selectedNotification = (Date) notificationDatePicker.getModel().getValue();
+ if (selectedNotification != null) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(selectedNotification);
+ MainFrame.tasks.get(index).setNotificationYear(cal.get(Calendar.YEAR));
+ MainFrame.tasks.get(index).setNotificationMonth(cal.get(Calendar.MONTH) + 1);
+ MainFrame.tasks.get(index).setNotificationDay(cal.get(Calendar.DAY_OF_MONTH));
+ }
+ MainFrame.tasks.get(index).setContent(contentTextArea.getText());
+ frame.dispose();
+ MainFrame.refreshMainFrame();
+ }
+ });
+ cp.add(saveButton);
+ // 取消
+ JButton cancelButton = new JButton("Cancel");
+ cancelButton.setBounds(220, 300, 100, 25);
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ frame.dispose();
+ }
+ });
+ cp.add(cancelButton);
+
+ frame.setVisible(true);
+ }
+
+ public static void Assigns(ServerResponse serverResponse, ClientInfo info, DataOutputStream serverOut, final Task task, int index) {
+ final JFrame assignFrame = new JFrame();
+ assignFrame.setSize(400, 400);
+ assignFrame.setLocation(200, 200);
+ assignFrame.setTitle("Assign Task");
+ assignFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+
+ cp = assignFrame.getContentPane();
+ cp.setLayout(null);
+
+ JLabel userLabel = new JLabel("Assign to User:");
+ userLabel.setBounds(50, 20, 120, 25);
+ cp.add(userLabel);
+
+ final JTextField userField = new JTextField();
+ userField.setBounds(180, 20, 160, 25);
+ cp.add(userField);
+
+ JButton assignButton = new JButton("Assign");
+ assignButton.setBounds(150, 200, 80, 25);
+ assignButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ String assignedUser = userField.getText();
+ task.addUser(assignedUser);
+ JOptionPane.showMessageDialog(assignFrame, "Task assigned to " + assignedUser);
+ assignFrame.dispose();
+ serverResponse.init();
+ serverResponse.setVisible(true);
+ if (!assignedUser.isEmpty()) {
+ try {
+ String taskData = task.toAssignString(assignedUser);
+ serverOut.writeBytes("ASSIGN_TASK" + " " + info.getSessionId() + " " + taskData + "\n");
+ }catch(IOException t) {
+ t.printStackTrace();
+ }
+ MainFrame.refreshMainFrame();
+ } else {
+ JOptionPane.showMessageDialog(assignFrame, "請輸入ID", "Error", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ });
+ cp.add(assignButton);
+
+ assignFrame.setVisible(true);
+ }
+}
diff --git a/src/client/TaskTracking.java b/src/client/TaskTracking.java
new file mode 100644
index 0000000..c4d0dcb
--- /dev/null
+++ b/src/client/TaskTracking.java
@@ -0,0 +1,94 @@
+package client;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class TaskTracking {
+ private static boolean ascendingOrder = true; // 用來確認當下的排序方法
+
+ public static void sortByStatus() {
+ List taskWithUsersList = new ArrayList<>();
+ for (Task task : MainFrame.tasks) {
+ taskWithUsersList.add(new TaskWithUsers(task, task.getUserIDs()));
+ }
+
+ Collections.sort(taskWithUsersList, new Comparator() {
+
+ public int compare(TaskWithUsers twu1, TaskWithUsers twu2) {
+ String status1 = twu1.task.getStatus();
+ String status2 = twu2.task.getStatus();
+ if (status1 == null && status2 == null) {
+ return 0;
+ } else if (status1 == null) {
+ return 1; // 將null放在最後
+ } else if (status2 == null) {
+ return -1; // 將null放在最後
+ } else {
+ int result = status1.compareTo(status2);
+ return ascendingOrder ? result : -result;
+ }
+ }
+ });
+
+ for (int i = 0; i < MainFrame.tasks.size(); i++) {
+ MainFrame.tasks.set(i, taskWithUsersList.get(i).task);
+ MainFrame.tasks.get(i).setUserIDs(taskWithUsersList.get(i).userIDs);
+ }
+
+ MainFrame.refreshMainFrame();
+ ascendingOrder = !ascendingOrder;
+ }
+
+ public static void sortByDate() {
+ List taskWithUsersList = new ArrayList<>();
+ for (Task task : MainFrame.tasks) {
+ taskWithUsersList.add(new TaskWithUsers(task, task.getUserIDs()));
+ }
+
+ Collections.sort(taskWithUsersList, new Comparator() {
+
+ public int compare(TaskWithUsers twu1, TaskWithUsers twu2) {
+ try {
+ Task task1 = twu1.task;
+ Task task2 = twu2.task;
+ if (task1.getYear() == 0 || task1.getMonth() == 0 || task1.getDay() == 0) {
+ return 1; // 將null放在最後
+ } else if (task2.getYear() == 0 || task2.getMonth() == 0 || task2.getDay() == 0) {
+ return -1; // 將null放在最後
+ } else {
+ Calendar cal1 = Calendar.getInstance();
+ cal1.set(task1.getYear(), task1.getMonth() - 1, task1.getDay());
+ Calendar cal2 = Calendar.getInstance();
+ cal2.set(task2.getYear(), task2.getMonth() - 1, task2.getDay());
+ int result = cal1.compareTo(cal2);
+ return ascendingOrder ? result : -result;
+ }
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+ });
+
+ for (int i = 0; i < MainFrame.tasks.size(); i++) {
+ MainFrame.tasks.set(i, taskWithUsersList.get(i).task);
+ MainFrame.tasks.get(i).setUserIDs(taskWithUsersList.get(i).userIDs);
+ }
+
+ MainFrame.refreshMainFrame();
+ ascendingOrder = !ascendingOrder;
+ }
+
+
+
+ static class TaskWithUsers {
+ Task task;
+ ArrayList userIDs;
+
+ TaskWithUsers(Task task, ArrayList userIDs) {
+ this.task = task;
+ this.userIDs = userIDs;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/database/DatabaseUtil.java b/src/database/DatabaseUtil.java
new file mode 100644
index 0000000..a91e7fb
--- /dev/null
+++ b/src/database/DatabaseUtil.java
@@ -0,0 +1,311 @@
+package database;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import client.Task;
+import task.TaskAssignment;
+import user.User;
+
+
+
+public class DatabaseUtil {
+
+ private static final String URL = "jdbc:mysql://localhost:3306/UserInformation"; // where you save data
+ private static final String USER = "root";
+ private static final String PASSWORD = "leo0909182463"; //user's password
+
+ // get connect with database
+ private static Connection Connect() throws SQLException {
+ return DriverManager.getConnection(URL, USER, PASSWORD);
+ }
+
+
+ // Placeholder for storing users and tasks in-memory
+ public static List userList = new ArrayList<>();
+ public static List assignData = new ArrayList<>();
+ public static List taskData = new ArrayList<>();
+
+
+ public synchronized static boolean AddTaskAssignments(String username, List taskAssignments) {
+ for(int i = 0;i < taskAssignments.size(); i++){
+ String sql = "INSERT INTO UserData(name, username, creator, userIDs, status, year, month, day, content, notificationYear, notificationMonth, notificationDay) VALUES(? ,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ try(Connection conn = Connect(); PreparedStatement pstmt = conn.prepareStatement(sql)){
+ TaskAssignment assigntask = taskAssignments.get(i);
+ pstmt.setString(1, assigntask.getName());
+ pstmt.setString(2, username);
+ pstmt.setString(3, assigntask.getTaskAssigner());
+ pstmt.setString(4, "");
+ pstmt.setString(5, assigntask.getStatus());
+ pstmt.setInt(6, assigntask.getYear());
+ pstmt.setInt(7, assigntask.getMonth());
+ pstmt.setInt(8, assigntask.getDay());
+ pstmt.setString(9, assigntask.getContent());
+ pstmt.setInt(10, assigntask.getNotificationYear());
+ pstmt.setInt(11, assigntask.getNotificationMonth());
+ pstmt.setInt(12, assigntask.getNotificationDay());
+ pstmt.executeUpdate();
+ }catch(SQLException e){
+ System.out.println(e.getMessage());
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Fetches new task assignments from the database.
+ * @param username The username of the user whose data be requested
+ * @return List of new TaskAssignment objects for the user.
+ */
+ public synchronized static List getNewTaskAssignments(String username) {
+ // Placeholder for actual database logic
+ List retuAssignments = new ArrayList<>();
+ String sql = "SELECT id, name, creator, status, year, month, day, content, notificationYear, notificationMonth, notificationDay FROM UserData WHERE username = ? AND username != creator";
+ try(Connection conn = Connect(); PreparedStatement pstmt = conn.prepareStatement(sql)){
+ pstmt.setString(1, username);
+ try(ResultSet rs = pstmt.executeQuery()){
+ while(rs.next()){
+ TaskAssignment task = new TaskAssignment(rs.getString("name"), rs.getString("status"), rs.getInt("year"), rs.getInt("month"), rs.getInt("day"), rs.getString("content"), rs.getInt("notificationYear"), rs.getInt("notificationMonth"), rs.getInt("notificationDay"), rs.getString("creator"));
+ retuAssignments.add(task);
+ String sql1 = "DELETE FROM UserData WHERE id = ?";
+ try(Connection conn1 = Connect(); PreparedStatement pstmt1 = conn1.prepareStatement(sql1)){
+ pstmt1.setInt(1, rs.getInt("id"));
+ pstmt1.executeUpdate();
+ }catch(SQLException e1){
+ System.out.println(e1.getMessage());
+ }
+ }
+ }
+ }catch(SQLException e){
+ System.out.println(e.getMessage());
+ }
+
+ return retuAssignments;
+ }
+
+ /**
+ * Assigns a task to a single user.
+ * @param task The task to be assigned.
+ * @param username The username of the user to whom the task is assigned.
+ * @return true if the assignment was successful, false otherwise.
+ */
+ public synchronized static boolean assignTaskToUser(TaskAssignment task, String username) {
+ // Placeholder for actual database logic
+ String sql = "INSERT INTO UserData(name, username, creator, userIDs, status, year, month, day, content, notificationYear, notificationMonth, notificationDay) VALUES(? ,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ try (Connection conn = Connect(); PreparedStatement pstmt = conn.prepareStatement(sql)) {
+ pstmt.setString(1, task.getName());
+ pstmt.setString(2, username);
+ pstmt.setString(3, task.getTaskAssigner());
+ pstmt.setString(4, "");
+ pstmt.setString(5, task.getStatus());
+ pstmt.setInt(6, task.getYear());
+ pstmt.setInt(7, task.getMonth());
+ pstmt.setInt(8, task.getDay());
+ pstmt.setString(9, task.getContent());
+ pstmt.setInt(10, task.getNotificationYear());
+ pstmt.setInt(11, task.getNotificationMonth());
+ pstmt.setInt(12, task.getNotificationDay());
+ pstmt.executeUpdate();
+ return true;
+ } catch (SQLException e) {
+ System.out.println(e.getMessage());
+ return false;
+ }
+ }
+
+ /**
+ * Updates the tasks in the database for a specific user.
+ * @param username The username of the user whose tasks are being updated.
+ * @param tasks List of tasks to be updated.
+ * @return true if the update was successful, false otherwise.
+ */
+ public synchronized static boolean updateTasksInDatabase(String username, List tasks) {
+ ArrayList taskIDs = new ArrayList<>();
+ // Placeholder for actual database logic
+ String sql = "SELECT id FROM UserData WHERE username = ? AND username = creator";
+ try(Connection conn = Connect(); PreparedStatement pstmt = conn.prepareStatement(sql)){
+ pstmt.setString(1, username);
+ try(ResultSet rs = pstmt.executeQuery()){
+ while(rs.next()){
+ taskIDs.add(rs.getInt("id"));
+ }
+ }
+ }catch(SQLException e){
+ System.out.println(e.getMessage());
+ return false;
+ }
+ for(int i = 0; i < Math.min(taskIDs.size(), tasks.size()); i++){
+ Task task = tasks.get(i);
+ int taskID = taskIDs.get(i);
+ sql = "UPDATE UserData SET name = ?, status = ?, year = ?, month = ?, day = ?, content = ?, notificationYear = ?, notificationMonth = ?, notificationDay = ?, userIDs = ? WHERE id = ?";
+ try(Connection conn = Connect(); PreparedStatement pstmt = conn.prepareStatement(sql)){
+ pstmt.setString(1, task.getName());
+ pstmt.setString(2, task.getStatus());
+ pstmt.setInt(3, task.getYear());
+ pstmt.setInt(4, task.getMonth());
+ pstmt.setInt(5, task.getDay());
+ pstmt.setString(6, task.getContent());
+ pstmt.setInt(7, task.getNotificationYear());
+ pstmt.setInt(8, task.getNotificationMonth());
+ pstmt.setInt(9, task.getNotificationDay());
+ pstmt.setString(10, String.join(",", task.getUserIDs()));
+ pstmt.setInt(11, taskID);
+ pstmt.executeUpdate();
+ }catch(SQLException e){
+ System.out.println(e.getMessage());
+ return false;
+ }
+ }
+ if(taskIDs.size() < tasks.size()){
+ for(int i = taskIDs.size(); i < tasks.size(); i++){
+ sql = "INSERT INTO UserData(name, username, creator, userIDs, status, year, month, day, content, notificationYear, notificationMonth, notificationDay) VALUES(? ,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ try(Connection conn = Connect(); PreparedStatement pstmt = conn.prepareStatement(sql)){
+ Task task = tasks.get(i);
+ pstmt.setString(1, task.getName());
+ pstmt.setString(2, username);
+ pstmt.setString(3, username);
+ pstmt.setString(4, String.join(",", task.getUserIDs()));
+ pstmt.setString(5, task.getStatus());
+ pstmt.setInt(6, task.getYear());
+ pstmt.setInt(7, task.getMonth());
+ pstmt.setInt(8, task.getDay());
+ pstmt.setString(9, task.getContent());
+ pstmt.setInt(10, task.getNotificationYear());
+ pstmt.setInt(11, task.getNotificationMonth());
+ pstmt.setInt(12, task.getNotificationDay());
+ pstmt.executeUpdate();
+ }catch(SQLException e){
+ System.out.println(e.getMessage());
+ return false;
+ }
+ }
+ }else if(taskIDs.size() > tasks.size()){
+ for(int i = tasks.size(); i < taskIDs.size(); i++){
+ sql = "DELETE FROM UserData WHERE id = ?";
+ try(Connection conn = Connect(); PreparedStatement pstmt = conn.prepareStatement(sql)){
+ pstmt.setInt(1, taskIDs.get(i));
+ pstmt.executeUpdate();
+ }catch(SQLException e){
+ System.out.println(e.getMessage());
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Initializes the task data for a user from the database.
+ * @param username The username of the user.
+ * @return A string representation of the user's tasks.
+ */
+ public synchronized static String initializeUserData(String username) {
+ // Placeholder for actual database logic
+ System.out.println("into init process");
+ String output_string = "";
+ String sql = "SELECT name, creator, userIDs, status, year, month, day, content, notificationYear, notificationMonth, notificationDay FROM UserData WHERE username = ? AND username = creator";
+ try(Connection conn = Connect(); PreparedStatement pstmt = conn.prepareStatement(sql)){
+ pstmt.setString(1, username);
+ try(ResultSet rs = pstmt.executeQuery()){
+ while(rs.next()){
+ String userIDs = rs.getString("userIDs");
+ String[] userIDsArray = userIDs.split(",");
+ ArrayList userIDsList = new ArrayList<>(Arrays.asList(userIDsArray));
+ Task task = new Task(rs.getString("name"), rs.getString("status"), rs.getInt("year"), rs.getInt("month"), rs.getInt("day"), rs.getString("content"), rs.getInt("notificationYear"), rs.getInt("notificationMonth"), rs.getInt("notificationDay"), userIDsList);
+ output_string += (task.toString() + ";");
+ }
+ }
+ }catch(SQLException e){
+ System.out.println(e.getMessage());
+ }
+ if (!output_string.isEmpty()) {
+ output_string = output_string.substring(0, output_string.length() - 1);
+ }
+
+ return output_string;
+ }
+
+ /**
+ * Finds a user by username in the database.
+ * @param username The username of the user to find.
+ * @return The User object if found, null otherwise.
+ */
+ public synchronized static User findByUsername(String username) {
+ // Placeholder for actual database logic
+ String sql = "SELECT id, username, password FROM UserAccount WHERE username = ?";
+ try(Connection conn = Connect(); PreparedStatement pstmt = conn.prepareStatement(sql)){
+ System.out.println("connectsuccess");
+ pstmt.setString(1, username);
+ try(ResultSet rs = pstmt.executeQuery()){
+ if(rs.next()){
+ User user = new User(rs.getString("username"), rs.getString("password"));
+ return user;
+ }
+ }
+ }catch(SQLException e){
+ System.out.println(e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * Adds a user to the database.
+ * @param user The User object to add.
+ */
+ public synchronized static void addUser(User user) {
+ // Placeholder for actual database logic
+ if(findByUsername(user.getUsername()) != null) {
+ System.out.println("usernmae have been used");
+ return;
+ }
+
+ String sql = "INSERT INTO UserAccount(username, password) VALUES(?, ?)";
+ try(Connection conn = Connect(); PreparedStatement pstmt = conn.prepareStatement(sql)){
+ pstmt.setString(1, user.getUsername());
+ pstmt.setString(2, user.getPassword());
+ pstmt.executeUpdate();
+ }catch(SQLException e){
+ System.out.println(e.getMessage());
+ }
+ }
+
+ /**
+ * Updates a user's password in the database.
+ * @param username The username of the user.
+ * @param newPassword The new password.
+ * @return true if the update was successful, false otherwise.
+ */
+ public synchronized static boolean updatePassword(String username, String newPassword) {
+ // Placeholder for actual database logic
+ User user = findByUsername(username);
+ if (user != null) {
+ user.setPassword(newPassword);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Updates a user's username in the database.
+ * @param oldUsername The current username of the user.
+ * @param newUsername The new username.
+ * @return true if the update was successful, false otherwise.
+ */
+ public synchronized static boolean updateUsername(String oldUsername, String newUsername) {
+ // Placeholder for actual database logic
+ User user = findByUsername(oldUsername);
+ if (user != null && findByUsername(newUsername) == null) {
+ user.setUsername(newUsername);
+ return true;
+ }
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/src/parameter/ErrorMsg.java b/src/parameter/ErrorMsg.java
new file mode 100644
index 0000000..344b1bb
--- /dev/null
+++ b/src/parameter/ErrorMsg.java
@@ -0,0 +1,8 @@
+package parameter;
+
+public enum ErrorMsg {
+ USER_NAME_BE_USED,
+ USER_NOT_EXIST,
+ PASSWORD_WRONG,
+ SUCCESS;
+}
diff --git a/src/parameter/ServerInMsg.java b/src/parameter/ServerInMsg.java
new file mode 100644
index 0000000..7fc1f92
--- /dev/null
+++ b/src/parameter/ServerInMsg.java
@@ -0,0 +1,27 @@
+package parameter;
+
+
+public enum ServerInMsg {
+ RE_UPDATE_TASK,
+ RE_ASSIGN,
+ RE_LOGOUT,
+ UPDATE_CHAT,
+ UPDATE_TASK,
+ INIT_CHAT,
+ INIT_TASK;
+
+
+ public static ServerInMsg getEnum(String value) {
+ if(value == null || value.length() < 1) {
+ return null;
+ }
+
+ for(ServerInMsg cmd : values()) {
+ if(cmd.name().equalsIgnoreCase(value)) {
+ return cmd;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/parameter/TaskCommand.java b/src/parameter/TaskCommand.java
new file mode 100644
index 0000000..a8df70a
--- /dev/null
+++ b/src/parameter/TaskCommand.java
@@ -0,0 +1,22 @@
+package parameter;
+
+public enum TaskCommand {
+ ASSIGN_TASK,
+ UPDATE_TASK,
+ USER_INIT_DATA;
+
+ // Handle enum, in case invalid command lead to IllegalArgumentException
+ public static TaskCommand getEnum(String value) {
+ if (value == null || value.length() < 1) {
+ return null;
+ }
+
+ for (TaskCommand cmd : values()) {
+ if (cmd.name().equalsIgnoreCase(value)) {
+ return cmd;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/parameter/Command.java b/src/parameter/UserCommand.java
similarity index 59%
rename from src/parameter/Command.java
rename to src/parameter/UserCommand.java
index 14df853..6d625df 100644
--- a/src/parameter/Command.java
+++ b/src/parameter/UserCommand.java
@@ -1,19 +1,19 @@
package parameter;
-// define command definition, used in ServiceThread class to declare hwo to action
-public enum Command {
+public enum UserCommand {
LOGIN,
+ LOGOUT,
REGISTRATION,
- EXIT;
+ SESSION_REFRESH;
// handle enum, in case invalid command lead IllegalArgumentException
- public static Command getEnum(String value) {
+ public static UserCommand getEnum(String value) {
if(value == null || value.length() < 1) {
return null;
}
- for(Command cmd : values()) {
+ for(UserCommand cmd : values()) {
if(cmd.name().equalsIgnoreCase(value)) {
return cmd;
}
@@ -22,5 +22,4 @@ public static Command getEnum(String value) {
return null;
}
-
}
diff --git a/src/server/Server.java b/src/server/Server.java
index 0e7e8e0..f9b0258 100644
--- a/src/server/Server.java
+++ b/src/server/Server.java
@@ -1,28 +1,43 @@
package server;
-import user.*;
import java.io.*;
import java.net.*;
+import sessionManagement.SessionManager;
+
public class Server {
public static final int PORT = 8000;
- public static UserService userservice = new UserService();
public static void main(String[] args) {
// open server socket
+ ServerSocket serversock = null;
+
try {
- ServerSocket serversock = new ServerSocket(PORT);
- System.out.println("Server end start...");
+ serversock = new ServerSocket(PORT);
+ System.out.println("Server start...");
+
while(true) {
Socket connectionSock = serversock.accept();
ServiceThread service = new ServiceThread(connectionSock);
Thread serviceThread = new Thread(service);
- serviceThread.run();
+ serviceThread.start();
}
}catch(IOException e ) {
System.out.println(e.getMessage());
+ }finally {
+ // Close server socket in finally block to release resources
+ if (serversock != null) {
+ try {
+ serversock.close();
+ } catch (IOException e) {
+ System.out.println("Error closing server socket: " + e.getMessage());
+ }
+ }
+
+ // shot down the scheduler
+ SessionManager.shutdownScheduler();
}
}
diff --git a/src/server/ServiceThread.java b/src/server/ServiceThread.java
index d9ad5bb..3b92b53 100644
--- a/src/server/ServiceThread.java
+++ b/src/server/ServiceThread.java
@@ -1,50 +1,77 @@
package server;
import user.*;
-import parameter.Command;
+import task.*;
+import parameter.*;
+import sessionManagement.SessionManager;
import java.io.*;
import java.net.*;
import java.util.StringTokenizer;
public class ServiceThread implements Runnable {
private Socket socket;
- private UserService userservice;
- private String request;
+ private UserCommandHandler ucm;
+ private TaskCommandHandler tcm;
+ private TaskUpdateChecker taskUpdateChecker;
public ServiceThread(Socket socket) {
- this.socket = socket;
- this.userservice = new UserService();
- }
+ this.socket = socket;
+ }
+
public void run() {
try {
BufferedReader clientIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
DataOutputStream clientOut = new DataOutputStream(socket.getOutputStream());
+ taskUpdateChecker = new TaskUpdateChecker(clientOut);
+ this.tcm = new TaskCommandHandler(taskUpdateChecker);
+ this.ucm = new UserCommandHandler(taskUpdateChecker);
+
while(true) {
+ String request = clientIn.readLine();
+ if (request == null) {
+ break; // Client disconnected
+ }
+
System.out.println("received client request :" + request);
StringTokenizer tokenizer = new StringTokenizer(request);
- Command command = Command.getEnum(tokenizer.nextToken());
+ String commandType = tokenizer.nextToken();
+ UserCommand userCommand = UserCommand.getEnum(commandType);
+ TaskCommand taskCommand = TaskCommand.getEnum(commandType);
- switch(command) {
- case LOGIN:
- break;
- case REGISTRATION:
- break;
- case EXIT:
- // send back to client say service close...
- break;
- default:
- break;
+ if(userCommand != null) {
+ ucm.handle(tokenizer, userCommand, clientOut);
+ }else if(taskCommand != null) {
+ tcm.handle(tokenizer, taskCommand, clientOut);
+ }else if("EXIT".equals(commandType)){
+ clientOut.writeBytes("Service close\n");
+ if(tokenizer.hasMoreTokens()) {
+ SessionManager.invalidateSession(tokenizer.nextToken());
+ }
+ clientIn.close();
+ socket.close();
+ break;
+ }else {
+ clientOut.writeBytes("Invalid Command\n");
}
-
-
+
}
}catch(IOException e) {
System.out.println(e.getMessage());
- }
-
-
-
+ }finally {
+ try {
+ if (taskUpdateChecker != null) {
+ taskUpdateChecker.stop();
+ }
+ if (socket != null && !socket.isClosed()) {
+ socket.close();
+ }
+ } catch (IOException e) {
+ System.out.println("Error closing socket: " + e.getMessage());
+ }
+ }
}
+
+
}
diff --git a/src/server/TaskUpdateChecker.java b/src/server/TaskUpdateChecker.java
new file mode 100644
index 0000000..bbc4b40
--- /dev/null
+++ b/src/server/TaskUpdateChecker.java
@@ -0,0 +1,65 @@
+package server;
+
+import database.DatabaseUtil;
+import task.TaskAssignment;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+public class TaskUpdateChecker implements Runnable {
+ private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+ private DataOutputStream clientOut;
+ private String username;
+
+ public TaskUpdateChecker(DataOutputStream clientOut) {
+ this.clientOut = clientOut;
+ }
+
+ public void start() {
+ if (scheduler.isShutdown() || scheduler.isTerminated()) {
+ scheduler = Executors.newScheduledThreadPool(1);
+ scheduler.scheduleAtFixedRate(this, 0, 20, TimeUnit.SECONDS);
+ }else {
+ scheduler.scheduleAtFixedRate(this, 0, 20, TimeUnit.SECONDS);
+ }
+ }
+
+ public void stop() {
+ scheduler.shutdown();
+ try {
+ if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
+ scheduler.shutdownNow();
+ }
+ } catch (InterruptedException e) {
+ scheduler.shutdownNow();
+ }
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public synchronized void run () {
+ List newAssignments = DatabaseUtil.getNewTaskAssignments(username);
+ try {
+ if(newAssignments.size() > 0) {
+ StringBuilder taskDataBuilder = new StringBuilder();
+ for(TaskAssignment taskAssignment : newAssignments) {
+ String taskData = taskAssignment.toString();
+ taskDataBuilder.append(taskData).append(";");
+ }
+ clientOut.writeBytes("UPDATE_TASK " + taskDataBuilder.toString() + "\n");
+ }
+ }catch(IOException e) {
+ e.printStackTrace();
+ }
+
+
+
+ }
+
+}
diff --git a/src/sessionManagement/SessionAutoUpdate.java b/src/sessionManagement/SessionAutoUpdate.java
new file mode 100644
index 0000000..38356fa
--- /dev/null
+++ b/src/sessionManagement/SessionAutoUpdate.java
@@ -0,0 +1,10 @@
+package sessionManagement;
+
+public class SessionAutoUpdate implements Runnable {
+
+ public void run() {
+
+ SessionManager.checkAndInvalidateExpiredSessions();
+
+ }
+}
diff --git a/src/sessionManagement/SessionManager.java b/src/sessionManagement/SessionManager.java
new file mode 100644
index 0000000..1fde64d
--- /dev/null
+++ b/src/sessionManagement/SessionManager.java
@@ -0,0 +1,102 @@
+package sessionManagement;
+
+import java.util.HashMap;
+import java.util.concurrent.*;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.UUID;
+
+public class SessionManager {
+ private static final long SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
+ private static final Map sessions = new HashMap<>();
+ private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+
+ static {
+ // Schedule the session cleanup task
+ scheduler.scheduleAtFixedRate(new SessionAutoUpdate(), 0, 30, TimeUnit.MINUTES);
+ }
+
+ public static synchronized String createSession(String username) {
+ String sessionId = UUID.randomUUID().toString();
+ long expirationTime = System.currentTimeMillis() + SESSION_TIMEOUT_MS;
+ Session session = new Session(sessionId, username, expirationTime);
+ sessions.put(sessionId, session);
+ return sessionId;
+ }
+
+ public static synchronized boolean isValidSession(String sessionId) {
+ Session session = sessions.get(sessionId);
+ return session != null && System.currentTimeMillis() <= session.getExpiryTime();
+ }
+
+ public static synchronized String getUsername(String sessionId) {
+ Session session = sessions.get(sessionId);
+ return session != null ? session.getUsername() : null;
+ }
+
+ public static synchronized void invalidateSession(String sessionId) {
+ if(sessionId == null) {
+ return;
+ }
+ sessions.remove(sessionId);
+ }
+
+ public static synchronized void checkAndInvalidateExpiredSessions() {
+ long currentTime = System.currentTimeMillis();
+ Iterator> iterator = sessions.entrySet().iterator();
+ while(iterator.hasNext()) {
+ Map.Entry entry = iterator.next();
+ if(entry.getValue().getExpiryTime() <= currentTime) {
+ iterator.remove();
+ }
+ }
+ }
+
+ public static synchronized boolean sessionRefresh(String sessionId) {
+ Session session = sessions.get(sessionId);
+ if(session == null) {
+ System.out.println("session not exist");
+ return false;
+ }
+
+ session.resetExpiryTime();
+ return true;
+ }
+
+ private static class Session {
+ private final String sessionId;
+ private final String username;
+ private long expirationTime;
+
+ public Session(String sessionId, String username, long expirationTime) {
+ this.sessionId = sessionId;
+ this.username = username;
+ this.expirationTime = expirationTime;
+ }
+
+ public long getExpiryTime() {
+ return this.expirationTime;
+ }
+
+ public void resetExpiryTime() {
+ this.expirationTime = System.currentTimeMillis() + SESSION_TIMEOUT_MS;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+ }
+
+
+ // call when server end, close the scheduler
+ public static void shutdownScheduler() {
+ scheduler.shutdown();
+ try {
+ if (!scheduler.awaitTermination(60, TimeUnit.SECONDS)) {
+ scheduler.shutdownNow();
+ }
+ } catch (InterruptedException e) {
+ scheduler.shutdownNow();
+ }
+ }
+}
diff --git a/src/task/TaskAssignment.java b/src/task/TaskAssignment.java
new file mode 100644
index 0000000..4e8fec7
--- /dev/null
+++ b/src/task/TaskAssignment.java
@@ -0,0 +1,30 @@
+package task;
+import client.Task;
+
+public class TaskAssignment extends Task {
+ private String taskAssigner;
+
+ public TaskAssignment(String name, String status, int year, int month, int day, String content, int notificationYear, int notificationMonth, int notificationDay, String taskAssigner) {
+ super(name, status, year, month, day, content, notificationYear, notificationMonth, notificationDay);
+ this.taskAssigner = taskAssigner;
+ }
+
+ public String getTaskAssigner() {
+ return taskAssigner;
+ }
+
+ @Override
+ public String toString() {
+ String taskData = this.getName() + "|" +
+ this.getStatus() + "|" +
+ this.getYear() + "|" +
+ this.getMonth() + "|" +
+ this.getDay() + "|" +
+ this.getContent() + "|" +
+ this.getNotificationYear() + "|" +
+ this.getNotificationMonth() + "|" +
+ this.getNotificationDay() + "|" +
+ this.taskAssigner;
+ return taskData;
+ }
+}
diff --git a/src/task/TaskCommandHandler.java b/src/task/TaskCommandHandler.java
new file mode 100644
index 0000000..09c7c4f
--- /dev/null
+++ b/src/task/TaskCommandHandler.java
@@ -0,0 +1,179 @@
+package task;
+import user.*;
+import server.TaskUpdateChecker;
+import database.DatabaseUtil;
+import client.Task;
+import sessionManagement.SessionManager;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.StringTokenizer;
+import parameter.TaskCommand;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+
+public class TaskCommandHandler {
+ private TaskUpdateChecker taskUpdateChecker;
+
+ public TaskCommandHandler(TaskUpdateChecker taskUpdateChecker) {
+ this.taskUpdateChecker = taskUpdateChecker;
+ }
+
+ public void handle(StringTokenizer tokenizer, TaskCommand command, DataOutputStream clientOut)throws IOException {
+ switch(command) {
+ case USER_INIT_DATA:
+ if(!handleInit(tokenizer, clientOut)) {
+ System.out.println("User init request data Faild");
+ }else {
+ System.out.println("User init request data sucess");
+ taskUpdateChecker.start();
+ }
+ break;
+ case UPDATE_TASK:
+ if(!handleUpdate(tokenizer, clientOut)) {
+ System.out.println("Database update Faild");
+ }else {
+ System.out.println("Database update sucess");
+ }
+ break;
+ case ASSIGN_TASK:
+ if(!handleAssign(tokenizer, clientOut)) {
+ System.out.println("Assign process Faild");
+ }else {
+ System.out.println("Assign process sucess");
+ }
+
+ break;
+ default:
+ clientOut.writeBytes("Invalid command\n");
+ }
+ }
+
+ private boolean handleInit(StringTokenizer tokenizer, DataOutputStream clientOut) throws IOException {
+
+ if (tokenizer.countTokens() < 1) {
+ clientOut.writeBytes("Invalid Command\n");
+ return false;
+ }
+
+ String sessionId = tokenizer.nextToken();
+ String username = SessionManager.getUsername(sessionId);
+ if(username == null) {
+ clientOut.writeBytes("INIT_TASK" + " Error" + " session is invalid, please relogin...." + "\n");
+ return false;
+ }
+
+ // Use user name to get the client's task list in the database
+ // This is a placeholder, replace with actual database update logic
+
+ // how task list be send to server:
+ // each task's attribute is separated by "|" and each task is separate by ";"
+ // the attribute "user id list" is use "," to separate elements in the list
+ // replace "file" below as real string
+ String initData = DatabaseUtil.initializeUserData(username);
+ taskUpdateChecker.setUsername(username);
+ clientOut.writeBytes("INIT_TASK SUCCESS " + initData + "\n");
+ return true;
+ }
+
+ private boolean handleUpdate(StringTokenizer tokenizer, DataOutputStream clientOut) throws IOException {
+ if (tokenizer.countTokens() < 2) {
+ clientOut.writeBytes("Invalid Command\n");
+ return false;
+ }
+
+ String sessionId = tokenizer.nextToken();
+ String username = SessionManager.getUsername(sessionId);
+ if(username == null) {
+ clientOut.writeBytes("RE_UPDATE_TASK Error\n");
+ return false;
+ }
+
+ List tasks = new ArrayList<>();
+ while (tokenizer.hasMoreTokens()) {
+ String taskData = tokenizer.nextToken(";");
+ String[] fields = taskData.split("\\|");
+ Task task = new Task(
+ fields[0], // name
+ fields[1], // status
+ Integer.parseInt(fields[2]), // year
+ Integer.parseInt(fields[3]), // month
+ Integer.parseInt(fields[4]), // day
+ fields[5], // content
+ Integer.parseInt(fields[6]), // notificationYear
+ Integer.parseInt(fields[7]), // notificationMonth
+ Integer.parseInt(fields[8]) // notificationDay
+ );
+ if(fields.length > 9 && fields[9] != null) {
+ task.setUserIDs(new ArrayList<>(Arrays.asList(fields[9].split(","))));
+ }
+
+ tasks.add(task);
+ }
+ boolean updateSuccess = DatabaseUtil.updateTasksInDatabase(username, tasks);
+
+ if (updateSuccess) {
+ clientOut.writeBytes("RE_UPDATE_TASK SUCCESS\n");
+ return true;
+ } else {
+ clientOut.writeBytes("RE_UPDATE_TASK FAIL\n");
+ return false;
+ }
+ }
+
+ private boolean handleAssign(StringTokenizer tokenizer, DataOutputStream clientOut) throws IOException {
+ if (tokenizer.countTokens() < 3) {
+ clientOut.writeBytes("Invalid Command\n");
+ return false;
+ }
+
+ String sessionId = tokenizer.nextToken();
+ String username = SessionManager.getUsername(sessionId);
+ if(username == null) {
+ clientOut.writeBytes("RE_ASSIGN" + " Error\n");
+ return false;
+ }
+
+ // how task list be send by client:
+ // each task's attribute is separated by "|", the attribute "user id list" is use "," to separate elements in the list
+ // use user name map to database to update the client's task list in database :
+ String taskData = tokenizer.nextToken("\n");
+ String[] fields = taskData.split("\\|");
+ if (fields.length < 10) {
+ clientOut.writeBytes("RE_ASSIGN Error\n");
+ return false;
+ }
+ // Create the task object
+ TaskAssignment task = new TaskAssignment(
+ fields[0], // name
+ fields[1], // status
+ Integer.parseInt(fields[2]), // year
+ Integer.parseInt(fields[3]), // month
+ Integer.parseInt(fields[4]), // day
+ fields[5], // content
+ Integer.parseInt(fields[6]), // notificationYear
+ Integer.parseInt(fields[7]), // notificationMonth
+ Integer.parseInt(fields[8]), // notificationDay
+ username // assigner
+ );
+
+ String target = fields[9];
+ boolean assignSuccess = false;
+ if(DatabaseUtil.findByUsername(target) != null) {
+ assignSuccess = DatabaseUtil.assignTaskToUser(task, target);
+ }else {
+ clientOut.writeBytes("RE_ASSIGN FAIL user not exist\n");
+ return false;
+ }
+
+ if (assignSuccess) {
+ clientOut.writeBytes("RE_ASSIGN SUCCESS\n");
+ return true;
+ } else {
+ clientOut.writeBytes("RE_ASSIGN FAIL\n");
+ return false;
+ }
+ }
+
+}
diff --git a/src/user/User.java b/src/user/User.java
index e7408bb..f2db6fe 100644
--- a/src/user/User.java
+++ b/src/user/User.java
@@ -7,9 +7,9 @@ public class User {
// init info
public User(String username, String password){
- System.out.println("Enter user name:");
+ System.out.println("user name:" + username);
this.username = username;
- System.out.println("Enter user password:");
+ System.out.println("user password:" + password);
this.password = password;
}
diff --git a/src/user/UserCommandHandler.java b/src/user/UserCommandHandler.java
new file mode 100644
index 0000000..7c82762
--- /dev/null
+++ b/src/user/UserCommandHandler.java
@@ -0,0 +1,146 @@
+package user;
+import parameter.*;
+import sessionManagement.*;
+import server.TaskUpdateChecker;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.StringTokenizer;
+
+public class UserCommandHandler {
+ private TaskUpdateChecker taskUpdateChecker;
+
+ public UserCommandHandler(TaskUpdateChecker taskUpdateChecker) {
+ this.taskUpdateChecker = taskUpdateChecker;
+ }
+
+ public void handle(StringTokenizer tokenizer, UserCommand command, DataOutputStream clientOut) throws IOException {
+ switch (command) {
+ case LOGIN:
+ if(!handleLogin(tokenizer, clientOut)) {
+ System.out.println("User Login Faild");
+ }else {
+ System.out.println("User login sucess");
+ }
+ break;
+ case LOGOUT:
+ if(!handleLogout(tokenizer, clientOut)) {
+ System.out.println("User Logout Faild");
+ }else {
+ System.out.println("User Logout success");
+ if(taskUpdateChecker != null) {
+ taskUpdateChecker.stop();
+ }
+ }
+ break;
+ case REGISTRATION:
+ if(!handleRegistration(tokenizer, clientOut)) {
+ System.out.println("Registeration Faild");
+ }else {
+ System.out.println("User Registeration success");
+ }
+ break;
+ case SESSION_REFRESH:
+ // this command is automatically send from client end
+ if(!handleSessionRefresh(tokenizer)) {
+ System.out.println("session refresh Faild");
+ }
+
+ break;
+ default:
+ clientOut.writeBytes("Invalid command\n");
+ }
+ }
+
+ private boolean handleLogin(StringTokenizer tokenizer, DataOutputStream clientOut) {
+ try {
+ if (tokenizer.countTokens() < 2) {
+ clientOut.writeBytes("Invalid Command\n");
+ return false;
+ }
+
+ String username = tokenizer.nextToken();
+ String password = tokenizer.nextToken();
+
+ switch (UserService.userLogin(username, password)) {
+ case SUCCESS:
+ String sessionId = SessionManager.createSession(username);
+ clientOut.writeBytes("Login Successfully! " + sessionId + "\n");
+ return true;
+ case USER_NOT_EXIST:
+ clientOut.writeBytes("Login failed: user not exist\n");
+ return false;
+ case PASSWORD_WRONG:
+ clientOut.writeBytes("Login failed: password wrong\n");
+ return false;
+ default:
+ clientOut.writeBytes("Login failed: unexpected error\n");
+ return false;
+ }
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ }
+ return false;
+ }
+
+
+ private boolean handleRegistration(StringTokenizer tokenizer, DataOutputStream clientOut) {
+ try {
+ if(tokenizer.countTokens() < 2) {
+ clientOut.writeBytes("Invalid Command");
+ return false;
+ }
+
+ String username = tokenizer.nextToken();
+ String password = tokenizer.nextToken();
+
+ switch(UserService.registerUser(username, password)) {
+ case SUCCESS:
+ clientOut.writeBytes("Registeration Sucessed\n");
+ return true;
+ case USER_NAME_BE_USED:
+ clientOut.writeBytes("Registeration Faild : username be used\n");
+ return false;
+ default:
+ clientOut.writeBytes("Registeration Faild : unexpected error\n");
+ return false;
+ }
+
+ }catch(IOException e) {
+ System.out.println(e.getMessage());
+ }
+ return false;
+ }
+
+ private boolean handleLogout(StringTokenizer tokenizer, DataOutputStream clientOut) {
+ try {
+ if (tokenizer.countTokens() < 1) {
+ clientOut.writeBytes("RE_LOGOUT " + "ERROR\n");
+ return false;
+ }
+
+ String sessionId = tokenizer.nextToken();
+ SessionManager.invalidateSession(sessionId);
+ clientOut.writeBytes("RE_LOGOUT " + "SUCCESS\n");
+ return true;
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ }
+
+ return false;
+ }
+
+ private boolean handleSessionRefresh(StringTokenizer tokenizer) {
+ if(tokenizer.countTokens() < 1) {
+ return false;
+ }
+
+ String sessionId = tokenizer.nextToken();
+ if(SessionManager.sessionRefresh(sessionId)) {
+ return true;
+ }
+
+ return false;
+ }
+
+
+}
diff --git a/src/user/UserService.java b/src/user/UserService.java
index 2dbf597..21ce2da 100644
--- a/src/user/UserService.java
+++ b/src/user/UserService.java
@@ -1,49 +1,65 @@
package user;
-import java.util.ArrayList;
-import java.util.List;
+import parameter.ErrorMsg;
+import database.DatabaseUtil;
public class UserService {
- private List userList = new ArrayList<>(); // replace by database implement, CRUD
-
- // this method need to switch search database not in-memory access
- public User findByUsername(String username) {
- for(User user : userList) {
- if(user.getUsername() == username) {
- return user;
- }
- }
- return null;
- }
-
- // register info and store back to database
- public boolean registerUser(String name, String password) {
- if(findByUsername(name) != null) {
- System.out.println("usernmae have been used");
- return false;
- }
-
- String hashedPassword = HashUtil.passwordHash(password);
-
- User user = new User(name, hashedPassword);
- userList.add(user);
- return true;
- // store back to databases
- }
-
- // once login complete, create a session to the login user
- public boolean userLogin(String username, String password) {
- User user = findByUsername(username);
-
- if(user != null && HashUtil.checkPassword(password, user.getPassword())) {
- // enter session part
- return true;
- }else if(user == null) {
- System.out.println("user not exist");
- }else {
- System.out.println("password wrong");
- }
- return false;
- }
+ // Register info and store back to database
+ public static ErrorMsg registerUser(String name, String password) {
+ if (DatabaseUtil.findByUsername(name) != null) {
+ System.out.println("Username has been used");
+ return ErrorMsg.USER_NAME_BE_USED;
+ }
+
+ String hashedPassword = HashUtil.passwordHash(password);
+ User user = new User(name, hashedPassword);
+ DatabaseUtil.addUser(user);
+ return ErrorMsg.SUCCESS;
+ }
+
+ public static ErrorMsg userLogin(String username, String password) {
+ User user = DatabaseUtil.findByUsername(username);
+ if (user != null && HashUtil.checkPassword(password, user.getPassword())) {
+ // Enter session part
+ return ErrorMsg.SUCCESS;
+ } else if (user == null) {
+ System.out.println("User not exist");
+ return ErrorMsg.USER_NOT_EXIST;
+ } else {
+ System.out.println("Password wrong");
+ return ErrorMsg.PASSWORD_WRONG;
+ }
+ }
+
+ public static boolean changePassword(String newPassword, String oldPassword, String username) {
+ User user = DatabaseUtil.findByUsername(username);
+
+ if (user == null) {
+ System.out.println("User: " + username + " not exist");
+ return false;
+ }
+
+ if (user != null && HashUtil.checkPassword(oldPassword, user.getPassword())) {
+ return DatabaseUtil.updatePassword(username, newPassword);
+ }
+
+ return false;
+ }
+
+ public static boolean changeUsername(String username, String newName) {
+ User user = DatabaseUtil.findByUsername(username);
+
+ if (user == null) {
+ System.out.println("User: " + username + " not exist");
+ return false;
+ }
+
+ if (DatabaseUtil.findByUsername(newName) != null) {
+ System.out.println("Name has been used");
+ return false;
+ } else {
+ return DatabaseUtil.updateUsername(username, newName);
+ }
+ }
}