A few days ago I posted a question about my code. It was obviously awful and thanks to some advice from Hosch250 I learnt a lot of things about OOP.
Now, I rewrote the program. To me it seems a little bit better than the previous one but I still feel that something is wrong.
In ServerSide.java there are 2 threads: one accepts new clients, and the other listens for messages from the clients. Since the second thread starts only after the first thread creates a Client
, I don't know why I should synchronize them. Both of the classes share a static list so I don't see the point to use synchronization.
I would like to avoid using the methods userClicksSubmit(String messages)
and appendMessage(String text)
as static, but I don't know how to.
ServerSide.java
public class ServerSide extends Thread {
private ServerSocket ss;
private Socket sock;
private int ID;
private static Map<Client, Integer> clientList = new HashMap<Client, Integer>();
private static PrintWriter pw;
int port;
// Main Constructor takes the port to connect to a server
// in order to chat with the clients
public ServerSide(int port) throws IOException {
this.port = port;
this.run();
}
@Override
public void run() {
try {
ss = new ServerSocket(port);
} catch (IOException e) {
e.printStackTrace();
}
receivingClients();
}
public void receivingClients() {
while (true) {
try {
sock = ss.accept();
clientList.put(new Client(sock, ID), ID);
ID++;
} catch (IOException e) {
e.printStackTrace();
}
}
}
//Static method that is called every time the server's user submits a message
public static void userClicksSubmit(String messages) throws IOException {
for (Map.Entry<Client, Integer> client : clientList.entrySet()) {
System.out.println(messages);
pw = new PrintWriter(client.getKey().getSock2().getOutputStream());
pw.println(messages);
pw.flush();
}
}
//////////////////////////// Receives the clients' messages ////////////////////////////
private class Client extends Thread{
private InputStreamReader inReader;
private BufferedReader buffReader;
private Socket sock2;
private PrintWriter pw2;
private int ID;
private String messages;
public Client(Socket sock2, int ID) throws IOException {
this.sock2 = sock2;
this.ID = ID;
this.start();
}
public void getMessages() throws IOException {
inReader = new InputStreamReader(sock2.getInputStream());
buffReader = new BufferedReader(inReader);
while ((messages = buffReader.readLine()) != null) {
//Static method of the Graphic Interface.It appends the messages to the textArea of the application
GraphicSide.appendMessage(messages);
//Send the received messages to all the clients of the map list with the exception of the sender
for (Map.Entry<Client, Integer> client : clientList.entrySet()) {
pw2 = new PrintWriter(client.getKey().getSock2().getOutputStream());
if (client.getValue() != ID) {
pw2.println(messages);
pw2.flush();
}
}
}
}
public Socket getSock2() {
return sock2;
}
@Override
public void run() {
try {
getMessages();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
GraphicSide.java
public class GraphicSide extends JFrame {
private JPanel contentPane;
private static JTextField textPort;
private JTextField textId;
private JButton submit;
private int port;
private static JTextArea textArea;
private static boolean agree = false;
private String text;
private String id;
public GraphicSide() {
setTitle("Login of the Server");
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setBounds(100, 100, 250, 355);
setVisible(true);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel portName = new JLabel("Port:");
portName.setHorizontalAlignment(SwingConstants.CENTER);
portName.setBounds(106, 102, 46, 14);
contentPane.add(portName);
textPort = new JTextField();
textPort.setHorizontalAlignment(SwingConstants.CENTER);
textPort.setToolTipText("e.g. 81");
textPort.setBounds(77, 127, 103, 20);
contentPane.add(textPort);
textPort.setColumns(10);
JLabel idLabel = new JLabel("Id:");
idLabel.setHorizontalAlignment(SwingConstants.CENTER);
idLabel.setBounds(106, 174, 46, 14);
contentPane.add(idLabel);
textId = new JTextField();
textId.setHorizontalAlignment(SwingConstants.CENTER);
textId.setToolTipText("e.g. Mike");
textId.setBounds(77, 199, 103, 20);
contentPane.add(textId);
textId.setColumns(10);
submit = new JButton("Submit");
submit.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
if (textId.getText().length() == 0 || textPort.getText().length() == 0) {
JOptionPane.showMessageDialog(null, "Compile all the fields", "Error", JOptionPane.WARNING_MESSAGE);
return;
}
setVisible(false);
try {
id = textId.getText();
new ChatWindow();
agree = true;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
submit.setBounds(94, 257, 74, 23);
contentPane.add(submit);
}
private class ChatWindow extends JFrame {
{
this.setTitle("Server");
this.setSize(750, 480);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setMinimumSize(new Dimension(750, 480));
GridBagLayout gridBagLayout_1 = new GridBagLayout();
gridBagLayout_1.columnWidths = new int[] { 0, 640, 70 };
gridBagLayout_1.rowHeights = new int[] { 387, 0, 0, 41, 40 };
gridBagLayout_1.columnWeights = new double[] { 1.0, 1.0 };
gridBagLayout_1.rowWeights = new double[] { 1.0, 0.0, 0.0, 1.0, Double.MIN_VALUE };
this.getContentPane().setLayout(gridBagLayout_1);
textArea = new JTextArea();
JScrollPane scroll = new JScrollPane(textArea);
DefaultCaret caret = new DefaultCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
textArea.setEditable(true);
textArea.setBorder(BorderFactory.createEtchedBorder());
GridBagConstraints gbc_textArea = new GridBagConstraints();
gbc_textArea.gridwidth = 3;
gbc_textArea.insets = new Insets(2, 2, 5, 2);
gbc_textArea.fill = GridBagConstraints.BOTH;
gbc_textArea.gridx = 0;
gbc_textArea.gridy = 0;
this.getContentPane().add(scroll, gbc_textArea);
JTextField textField = new JTextField();
textField.setBorder(BorderFactory.createEtchedBorder());
GridBagConstraints gbc_textArea_1 = new GridBagConstraints();
gbc_textArea_1.gridheight = 2;
gbc_textArea_1.gridwidth = 2;
gbc_textArea_1.fill = GridBagConstraints.BOTH;
gbc_textArea_1.insets = new Insets(2, 2, 2, 5);
gbc_textArea_1.gridx = 0;
gbc_textArea_1.gridy = 3;
this.getContentPane().add(textField, gbc_textArea_1);
this.setVisible(true);
JButton btnNewButton = new JButton("Send");
btnNewButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
text = textField.getText();
try {
ServerSide.userClicksSubmit(textId.getText()+" : " +text);
} catch (IOException e) {
e.printStackTrace();
}
textArea.append(text + '\n');
textField.setText("");
}
});
textField.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "enter");
AbstractAction pressedAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent arg0) {
// Here you put the code that is run when you press the key
btnNewButton.doClick();
System.out.println("Key pessed");
}
};
textField.getActionMap().put("enter", pressedAction);
GridBagConstraints gbc_btnNewButton = new GridBagConstraints();
gbc_btnNewButton.gridheight = 2;
gbc_btnNewButton.gridx = 2;
gbc_btnNewButton.gridy = 4;
this.getContentPane().add(btnNewButton, gbc_btnNewButton);
}
}
public static void appendMessage(String text) {
textArea.append(text + '\n');
}
public boolean isAgree() {
return agree;
}
public int getPort() {
return port = Integer.parseInt(textPort.getText());
}
}
MainClass.java
import java.io.IOException;
import javax.swing.JFrame;
public class MainClassApp extends JFrame {
private static final long serialVersionUID = 1L;
public static void main(String[] args) throws IOException, InterruptedException {
GraphicSide gs = new GraphicSide();
//Starts the server class only after the user inserts a port and presses the submit button on the GUI
//application
while (true) {
if (gs.isAgree() == true) {
break;
}
}
new ServerSide(gs.getPort());
}
}