JScrollPanel is not responding initially - java

I wanted to make a chat server client with GUI. Any new messages will be added as a JPanel. Initially messages added to my JScrollPanel is updating smoothly. However when i implemented the server and client to work with the GUI, the first few new messages added are never updated. Messages will only be updated to the JScrollPanel after the third add onward. Some times the adding of components ended prematurely. The client implements runnable so any new messages will be updated to the JScrollPanel via a Thread.
It seems like the GUI did not fully initialise.
this is the Client code
public static void main(String[] args) {
new Thread(new MessageClient("htf0001")).start();
MessageGUI dialog = new MessageGUI(collaID);
}
#Override
public void run() {
//loop read from server
// The default port.
int portNumber = 50000;
// The default host.
String host = "localhost";//"54.169.62.79";
/*
* Open a socket on a given host and port. Open input and output streams.
*/
try {
clientSocket = new Socket(host, portNumber);
oos = new ObjectOutputStream(clientSocket.getOutputStream());
oos.flush();
ois = new ObjectInputStream(clientSocket.getInputStream());
Staff staff = new Staff();
sendToServer(staff.connectToMessageServer(collaID));
sendToServer(staff.getMessageLog(collaID));
while(!close){
ArrayList<String> input = new ArrayList<String>();
Object o = ois.readObject();
input = (ArrayList<String>) o;
if(input.get(0).compareTo("end")!=0){
for(int i=0;i<input.size();i=i+5){
MessageGUI.addMessage(input.get(i),input.get(i+1), input.get(i+2),
input.get(i+3),input.get(i+4));
}
}
else close = true;
}
oos.close();
ois.close();
clientSocket.close();
}
catch (UnknownHostException uhe) {
JOptionPane.showMessageDialog(null,uhe.getMessage());
}
catch (IOException ioe) {
JOptionPane.showMessageDialog(null,ioe.getMessage());
}
catch (ClassNotFoundException ex) {
JOptionPane.showMessageDialog(null,ex.getMessage());
}
}
this is the GUI code part that add in the component
public static void addMessage(String date, String firstName, String lastName,
String message, String time){
String newUser = firstName + " " + lastName;
if(recentDate.compareTo(date)!=0){
JLabel newDate = new JLabel(date);
newDate.setHorizontalAlignment(SwingConstants.CENTER);
addComponent(newDate,nextLine,0,3,1);
recentDate = date;
nextLine++;
}
if(recentUser.compareTo(newUser)==0 && recentTime.compareTo(time)==0){
recentJTextArea.append("\n\n"+message);
}
else{
if(recentUser.compareTo(newUser)==0) newUser = recentUser;
JTextArea temp = new JTextArea();
temp.setFocusable(false);
temp.setBorder(BorderFactory.createTitledBorder(newUser));
temp.setLineWrap(true);
temp.setWrapStyleWord(true);
temp.setEditable(false);
temp.setText(message);
recentJTextArea = temp;
recentUser = newUser;
JLabel newTime = new JLabel(time);
newTime.setHorizontalAlignment(SwingConstants.RIGHT);
recentTime = time;
addComponent(temp,nextLine,0,2,1);
nextLine = nextLine + 1;
addComponent(newTime,nextLine,1,1,1);
nextLine = nextLine + 1;
}
invokeLater(new Runnable() {
public void run() {
ChatLogJScrollPane.getVerticalScrollBar().setValue(ChatLogJScrollPane.getVerticalScrollBar().getMaximum());
}
});
}

Seems like you are updating (ie adding the chat text) to your text areas on a thread that is not the GUI thread. Instead, you should call
SwingUtilities.invokeLater(new Runnable() {
temp.setText(message);
temp.repaint();
});

I've found the solution. I need to validate the JPanel in my JScrollPanel.
JPanel container
JScrollPanel(container)
SwingUtilities.invokeLater(new Runnable(){
container.validate();
});

Related

Handle Java Socket connection between 2 JFrames

I'm trying to create a client/server application using sockets, I have 2 JFrames (2 seperate classes) , a user will initially open up the one frame and there's a button to go to the other JFrame, when clicked it disposes the previous frame and opens the new frame.
I'd like to know how I could switch back and forth between these 2 JFrames without my program crashing and needing to forcefully close, I am establishing the connection in the constructor of each JFrame.
try {
server = new Socket("localhost", PORT);
// creates & instantiates objectInput and output streams
getStreams();
} catch (IOException ex) {
System.out.println("error creating socket: " + ex.getMessage());
}
I have these in the constructor of both JFrames
EDIT
Server
public class Testserver {
private ServerSocket serverSocket;
private Socket client;
private final int PORT = 5432;
private ObjectOutputStream objectOutputStream;
private ObjectInputStream objectInputStream;
public Testserver() {
try {
serverSocket = new ServerSocket(PORT);
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, "Error: " + ex.getMessage());
System.out.println("error creating server socket: " + ex.getMessage());
}
}
private void listenForClient() {
try {
System.out.println("Server is running and is waiting/listening for a connection to be established.");
////JOptionPane.showMessageDialog(null, "Server is running and is waiting/listening for a connection to be established." );
client = serverSocket.accept();
System.out.println("A client has connected");
objectOutputStream = new ObjectOutputStream(client.getOutputStream());
objectInputStream = new ObjectInputStream(client.getInputStream());
processClient();
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, "Error: " + ex.getMessage());
}
}
private void processClient() {
do {
try {
String messageFromClient = (String) objectInputStream.readObject();
// check for clients requests and handle them (database etc)
System.out.println("[CLIENT] " + messageFromClient);
} catch (IOException ex) {
Logger.getLogger(Testserver.class.getName()).log(Level.SEVERE, null, ex);
break;
} catch (ClassNotFoundException ex) {
Logger.getLogger(Testserver.class.getName()).log(Level.SEVERE, null, ex);
break;
}
} while (true);
closeConnections();
}
private void closeConnections() {
try {
objectInputStream.close();
objectInputStream.close();
client.close();
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, "Error: " + ex.getMessage());
}
}
public static void main(String[] args) {
new Testserver().listenForClient();
}
}
CustomerGUI
public class CustomerGUI extends JFrame implements ActionListener{
private Socket server;
private ObjectOutputStream objectOutputStream;
private ObjectInputStream objectInputStream;
private JPanel panel1;
private JButton btnAdminGUI;
private final int PORT = 5432;
public CustomerGUI() {
btnAdminGUI = new JButton("Go to Admin GUI");
try {
server = new Socket("localhost", PORT);
System.out.println("Connected to server");
objectOutputStream = new ObjectOutputStream(server.getOutputStream());
objectInputStream = new ObjectInputStream(server.getInputStream());
objectOutputStream.writeObject("from Customer");
objectOutputStream.flush();
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, "Error: " + ex.getMessage()););
}
btnAdminGUI.addActionListener(this);
}
public void setGUI() {
add(btnAdminGUI);
setSize(300, 400);
setVisible(true);
}
public static void main(String[] args) {
new CustomerGUI().setGUI();
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == btnAdminGUI) {
new AdminGUI().setGUI();
dispose();
}
}
}
AdminGUI
public class AdminGUI extends JFrame implements ActionListener{
private Socket server;
private ObjectOutputStream objectOutputStream;
private ObjectInputStream objectInputStream;
private JPanel panel1;
private JButton btnCustomerGUI;
private final int PORT = 5432;
public AdminGUI() {
btnCustomerGUI = new JButton("Go to Customer GUI");
try {
server = new Socket("localhost", PORT);
System.out.println("Connected to server");
objectOutputStream = new ObjectOutputStream(server.getOutputStream());
objectInputStream = new ObjectInputStream(server.getInputStream());
objectOutputStream.writeObject("from Admin");
objectOutputStream.flush();
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, "Error: " + ex.getMessage());
}
btnCustomerGUI.addActionListener(this);
}
public void setGUI() {
add(btnCustomerGUI);
setSize(300, 400);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == btnCustomerGUI) {
new CustomerGUI().setGUI();
dispose();
}
}
}
I'll post a solution this because I have done something similar recently, but I don't have a UI for it yet.
The idea is MVC, with two models, a Server and Client and there are two Views, JPanels, which can be displayed in a window/jframe/dialog, whichever is appropriate. The Controller is essentially an api for interacting with the model, for this simple example the controllers will be mixed with the models. I think this example has a lot of flaws, but I think it gives a good idea of what needs to be done.
A button starts a course of action,
serverControls.addActionListener( evt ->{ } );
The button does one of two actions, either it starts the server or it stops the server.
serverLoop.submit( ()->{
server.listen();
//should notify a listener that the server has stopped.
});
serverLoop is another thread of execution, server.listen() is a long running task. It shouldn't return until we want the server to stop listening.
The other button is on the client. It has a similar structure..
clientControls.addActionListener( evt->{
clientLoop.submit( () -> client.connect( server ) );
clientLoop.submit(
() -> SwingUtilities.invokeLater(
() -> response.setText( client.communicate() )
)
);
});
First the client is going to connect, then it communicates.
import javax.swing.*;
import java.util.concurrent.*;
public class ClientServerApp{
static class Server{
volatile boolean available = false;
public void listen(){
try{
available = true;
synchronized( this ){
wait(5000);
}
} catch(Exception e){
e.printStackTrace();
//if the server terminates unexpectedly.
}finally{
available = false;
}
}
public void stopListening(){
}
}
static class Client{
Server connected;
public void connect(Server host){
connected = host;
}
public String communicate(){
if(connected != null){
if(connected.available){
return "connected";
} else{
return "cannot connect";
}
}
return "no host";
}
}
public static void main(String[] args){
Server server = new Server();
Client client = new Client();
ExecutorService serverLoop = Executors.newSingleThreadExecutor();
JPanel serverView = new JPanel();
JButton serverControls = new JButton("start");
serverView.add( serverControls );
serverControls.addActionListener( evt ->{
if(serverControls.getText().equals("start") ){
serverControls.setText("stop");
serverLoop.submit( ()->{
server.listen();
//should notify a listener that the server has stopped.
});
} else{
server.stopListening();
serverLoop.submit( ()->{
//will be run after the listen loop has completed.
SwingUtilities.invokeLater( () - >
serverControls.setText("start")
);
});
}
} );
JPanel clientView = new JPanel();
JButton clientControls = new JButton("connect");
JTextField response = new JTextField(40);
clientView.add( clientControls );
clientView.add(response);
ExecutorService clientLoop = Executors.newSingleThreadExecutor();
System.out.println("creating client action listener");
clientControls.addActionListener( evt->{
clientLoop.submit( () -> client.connect( server ) );
clientLoop.submit( () ->
SwingUtilities.invokeLater(
() -> response.setText( client.communicate() )
)
);
});
JFrame mainWindow = new JFrame();
mainWindow.setContentPane( serverView);
mainWindow.pack();
mainWindow.setVisible(true);
JDialog clientWindow = new JDialog( mainWindow, "Client Window");
clientWindow.setContentPane(clientView);
clientWindow.pack();
clientWindow.setVisible(true);
}
}
In a more complete example, you would probably have a Listener interface, so that your swing gui can response to changes in state of the server or the client, and a controller that manages the threads.

Cant append to JTextArea

I'm trying to create a text chat with Java. I have a Server and a Client that connect to each other using Streams, and send data using the objectInputStream and objectOutputStream.
I have GUI's for both the client and the server.
I made these GUI's using intellij's GUI Form.
server GUI form image
The problem I'm having is when I try to display text to the GUI of the server. I can append to the GUi if I call my relayToAll method from the JTextField actionlistener, which then send the message to all the clients and prints it out in the servers GUI.
If i try to call the same method from where I receive the input, then the append to the text area does not work.
Can anyone tell me why its not appending?
Thanks
public class ServerTest {
private JTextField textField1;
private JTextArea textArea1;
private JPanel Panel;
static private ObjectOutputStream objectOutputStream;
static private ObjectInputStream objectInputStream;
static private Socket client;
static private ArrayList<Socket> clients = new ArrayList<Socket>();
static private ArrayList<ObjectOutputStream> objectOutputStreams = new ArrayList<>();
public void relayToAll(String message){
try {
for(int i = 0; i < clients.size(); i++) {
ObjectOutputStream output = objectOutputStreams.get(i);
output.writeObject(message);
output.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
appendTextArea(message);
}
public void appendTextArea(String text){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
System.out.println("This should go to the Server GUI: " + text);
textArea1.append(text + "\n");
}
});
}
public ServerTest() {
textField1.addActionListener(e -> {
System.out.println(e.getActionCommand());
relayToAll(e.getActionCommand());
textField1.setText("");
});
}
public void ReadInput(ObjectInputStream input, int port){
try {
String oldMessage = "";
while (true) {
String message = (String) input.readObject();
if (message != oldMessage){
System.out.println(port + ": " + message);
oldMessage = message;
relayToAll(port + ": " + message);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public void IOSetup(){
try {
ServerSocket serverSocket = new ServerSocket( 6969 );
ExecutorService executor = Executors.newFixedThreadPool(5);
System.out.println("server on\n");
for (int i = 0; i < 5; i++){
client = serverSocket.accept();
clients.add(client);
System.out.println("Connection from: "+ client.getPort());
objectOutputStream = new ObjectOutputStream(client.getOutputStream());
objectOutputStreams.add(objectOutputStream);
objectInputStream = new ObjectInputStream(clients.get(i).getInputStream());
executor.submit(() -> {
ReadInput(objectInputStream, client.getPort());
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Server");
frame.setContentPane(new ServerTest().Panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
ServerTest application = new ServerTest();
application.IOSetup();
}
Actually you've got kind of a silly mistake. Please check lines (A) and (B) below:
public static void main(String[] args) {
JFrame frame = new JFrame("Server");
frame.setContentPane(new ServerTest().Panel); // *************** (A)
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
ServerTest application = new ServerTest(); // *************** (B)
application.IOSetup();
}
Do you see a problem? You're creating TWO ServerTest objects, one that has its Panel variable added to the JFrame and that gets displayed, and the other that is set up for IO communication. The ActionListener changes the state of the displayed JTextArea while the IO communications changes the state of a JTextArea that is in the second ServerTest instance, the one not displayed.
One improvement is to create only one instance:
public static void main(String[] args) {
ServerTest application = new ServerTest(); // create one instance
JFrame frame = new JFrame("Server");
// frame.setContentPane(new ServerTest().Panel);
frame.setContentPane(application.Panel); // and use in both places
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
//ServerTest application = new ServerTest();
application.IOSetup(); // and use in both places
}
Other problems:
You've got long-running code long running and blocking in a background thread, and that is potentially dangerous, and the only reason that your GUI is not getting frozen is because you're starting the GUI (incorrectly) on the main thread and off of the Swing event thread. For more on this, you will want to read up on Swing concurrency: Lesson: Concurrency in Swing
You will want to learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others.

Update Swing GUI from other thread

I have two classes, one of them is my thread in which I read outputs from a device through TCP/IP:
public static controlPanel cp = new controlPanel();
void startListenForTCP (final String ipaddress){
Thread TCPListenerThread;
TCPListenerThread = new Thread(new Runnable() {
#Override
public void run() {
Boolean run = true;
String serverMessage = null;
InetAddress serverAddr = null;
BufferedWriter out = null;
try
(Socket clientSocket = new Socket(ipaddress, 7420)) {
cp.updateGUI("Connection initiated... waiting for outputs!"+"\n");
char[] buffer = new char[2];
int charsRead = 0;
out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while ((charsRead = in.read(buffer)) != -1)
{
String message = new String(buffer).substring(0, charsRead);
switch (message) {
case "o,":
cp.updateGUI("Čekanje da loptica prođe RFID čitač!");
break;
case "y,":
cp.updateGUI("Hardverski problem!");
break;
case "Y,":
cp.updateGUI("Loptica nije izažla, hardverski problem!");
break;
case "I,":
cp.updateGUI("Uređaj u stanju mirovanja!!");
break;
default:
String m = message;
m = m.replaceAll("[^\\d.]", "");
try{
int i = Integer.parseInt(m);
System.out.println("Is int: "+i);
int izasao=Integer.parseInt(m);
if (redni>34){
redni=0;
}
if (izasao>0 && izasao<49){
redni =redni+1;
m=m;
ur.updateResults(redni, m);
bs.testAuto(m, redni);
System.out.println(m+ "\n");
}
} catch(NumberFormatException e){
} break;
}
}}
catch(UnknownHostException e) {
System.out.println("Unknown host..."+"\n");
} catch(IOException e) {
System.out.println("IO Error..."+"\n");
}
}
});
TCPListenerThread.start();
}
The other one is swing form in which i want to set jLabel text from the class above:
Public class controlPanel extends javax.swing.JFrame {
public static gameControler gc = new gameControler();
public controlPanel() {
initComponents();
}
public void updateGUI(final String text) {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
updateGUI(text);
}
});
}jLabel5.setText(text);
System.out.println(text);
}
The message gets printed out in console but i can't set it's value to jLabel.
I need a quick way to achieve this, so any workarounds will be most helpfull.
Thank you,
Your code only updates the GUI if current thread is not the EDT:
if (!SwingUtilities.isEventDispatchThread()) {
// you call SwingUtilities.invokeLater();
}
The GUI update should also happen if the current thread happens to be the EDT. So you should change it to somehting like this:
if (SwingUtilities.isEventDispatchThread())
jLabel5.setText(text);
else
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
jLabel5.setText(text);
}
});
Note that invokeLater() is not executed immediately but asynchronously some time later. If you need the update to happen before it returns, use SwingUtilities.invokeAndWait().
Also note that you may consider using the SwingWorker class to perform lengthy GUI-interaction tasks in a background thread.
Making it utility method
If you have to do this many times, it is profitable to make a utilitiy method for this:
public void callFromEdt(Runnable task) {
if (SwingUtilities.isEventDispatchThread())
task.run();
else
SwingUtilities.invokeLater(task); // You might want to consider
// using invokeAndWait() instead
}

How to update JComboBox content from ArrayList?

I have JComboBox based on ArrayList:
private ArrayList<String> klienci = new ArrayList<String>();
private JComboBox klienciLista;
and I add it in constructor:
klienciLista = new JComboBox(klienci.toArray());
klienciLista.setPrototypeDisplayValue("#############################");
panel.add(klienciLista); //JPanel panel
At the start List is empty. Client gets via socket new ArrayList in thread:
public void run() {
try {
host = InetAddress.getLocalHost().getHostName();
socket = new Socket(host, SERVER_PORT);
input = new ObjectInputStream(socket.getInputStream());
output = new ObjectOutputStream(socket.getOutputStream());
output.writeObject(nazwa);
} catch (IOException e) {
System.out.println(e);
JOptionPane.showMessageDialog(null,
"Polaczenie sieciowe dla klienta nie moze byc utworzone");
setVisible(false);
dispose(); // zwolnienie zasobów graficznych
// okno graficzne nie zostanie utworzone
return;
}
try {
while (true) {
container = new Object[2];
container = (Object[]) input.readObject();
String m = (String) container[0];
setKlienci((ArrayList<String>) container[1]);
klienciLista = new JComboBox(klienci.toArray());
String pom = textArea.getText();
textArea.setText(pom + ">>> " + m + "\n");
klienciLista.revalidate();
panel.revalidate();
panel.repaint();
if (m.equals("exit")) {
input.close();
output.close();
socket.close();
setVisible(false);
dispose();
break;
}
}
} catch (Exception e) {
System.out.println(e);
JOptionPane.showMessageDialog(null,
"Polaczenie sieciowe dla klienta zostalo przerwane");
setVisible(false);
dispose();
}
}
What I want to do is that my JComboBox klienciLista fill with new ArrayList of available clients, but that does not happen. After connecting, the server sends arrayList and client updates it but doesn't update ComboBox. Why is this?
It's because you keep creating a new JComboBox in your loop, instead of updating the existing one.
Instead of
while(true){
...
klienciLista = new JComboBox(klienci.toArray());
...
}
do:
while(true){
...
klienciLista.removeAllItems();
for(String s:klienci){
klienciLista.addItem(s);
}
...
}
or, preferably, use a model:
klienciLista.setModel(new DefaultComboBoxModel(klienci.toArray()));
This is because you are creating a new JComboBox instead of updating the one on the GUI.
Look at the addItem() method on the JComboBox: http://download.oracle.com/javase/6/docs/api/javax/swing/JComboBox.html
First, you should create you JComboBox from a ComboBoxModel. Second, you shouldn't be calling new JComboBox inside the loop.
Because when you do
klienciLista = new JComboBox(klienci.toArray());
you are creating a new JComboBox and referencing it through that variable, but the original JComboBox still exists in the GUI. You have done nothing to change the JComboBox that is currently displayed.
Clear and update your list not your comboBox.

Server and Client using Sockets

Are there any examples of a server and a client that use sockets, but that have send and get methods? I'm doing this networked battleship program, almost finished, but can't get the server and clients to work. I have made a chat program that only sends strings, but this time I need to send objects. I'm already frustrated, so is there any source code that already has this.
Here's the code for the client... how would you modify it to allow to send objects? Also I need to be listening for incoming objects and process them right away.
import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SimpleChat extends JFrame {
private Socket communicationSocket = null;
private PrintWriter outStream = null;
private BufferedReader inStream = null;
private Boolean communicationContinue = true;
private String disconnectString = "disconnect764*#$1";
private JMenuItem disconnectItem;
private JTextField displayLabel;
private final Color colorValues[] = { Color.black, Color.blue, Color.red, Color.green };
// set up GUI
public SimpleChat() {
super("Simple Chat");
// set up File menu and its menu items
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic('F');
// set up Activate Server menu item
JMenuItem serverItem = new JMenuItem("Activate Server");
serverItem.setMnemonic('S');
fileMenu.add(serverItem);
serverItem.addActionListener(new ActionListener() { // anonymous inner class
// display message dialog when user selects About...
public void actionPerformed(ActionEvent event) {
setUpServer();
}
} // end anonymous inner class
); // end call to addActionListener
// set up Activate Client menu item
JMenuItem clientItem = new JMenuItem("Activate Client");
clientItem.setMnemonic('C');
fileMenu.add(clientItem);
clientItem.addActionListener(new ActionListener() { // anonymous inner class
// display message dialog when user selects About...
public void actionPerformed(ActionEvent event) {
setUpClient();
}
} // end anonymous inner class
); // end call to addActionListener
// set up Activate Client menu item
disconnectItem = new JMenuItem("Disconnect Client/Server");
disconnectItem.setMnemonic('D');
disconnectItem.setEnabled(false);
fileMenu.add(disconnectItem);
disconnectItem.addActionListener(new ActionListener() { // anonymous inner
// class
// display message dialog when user selects About...
public void actionPerformed(ActionEvent event) {
disconnectClientServer(true);
}
} // end anonymous inner class
); // end call to addActionListener
// set up About... menu item
JMenuItem aboutItem = new JMenuItem("About...");
aboutItem.setMnemonic('A');
fileMenu.add(aboutItem);
aboutItem.addActionListener(new ActionListener() { // anonymous inner class
// display message dialog when user selects About...
public void actionPerformed(ActionEvent event) {
JOptionPane.showMessageDialog(SimpleChat.this, "This is an example\nof using menus", "About",
JOptionPane.PLAIN_MESSAGE);
}
} // end anonymous inner class
); // end call to addActionListener
// set up Exit menu item
JMenuItem exitItem = new JMenuItem("Exit");
exitItem.setMnemonic('x');
fileMenu.add(exitItem);
exitItem.addActionListener(new ActionListener() { // anonymous inner class
// terminate application when user clicks exitItem
public void actionPerformed(ActionEvent event) {
disconnectClientServer(true);
System.exit(0);
}
} // end anonymous inner class
); // end call to addActionListener
// create menu bar and attach it to MenuTest window
JMenuBar bar = new JMenuBar();
setJMenuBar(bar);
bar.add(fileMenu);
// set up label to display text
displayLabel = new JTextField("Sample Text", SwingConstants.CENTER);
displayLabel.setForeground(colorValues[0]);
displayLabel.setFont(new Font("Serif", Font.PLAIN, 72));
displayLabel.addActionListener(new ActionListener() { // anonymous inner
// class
// display message dialog when user selects About...
public void actionPerformed(ActionEvent event) {
sendData();
}
} // end anonymous inner class
); // end call to addActionListener
getContentPane().setBackground(Color.CYAN);
getContentPane().add(displayLabel, BorderLayout.CENTER);
setSize(500, 200);
setVisible(true);
} // end constructor
public static void main(String args[]) {
final SimpleChat application = new SimpleChat();
application.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
application.disconnectClientServer(true);
System.exit(0);
}
});
// application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
public void setCommunicationSocket(Socket sock) {
communicationSocket = sock;
communicationContinue = true;
disconnectItem.setEnabled(true);
}
public void setOutStream(PrintWriter out) {
outStream = out;
}
public void setInStream(BufferedReader in) {
inStream = in;
}
public void setUpServer() {
ServerThread st = new ServerThread(this);
st.start();
}
public void setUpClient() {
ClientThread st = new ClientThread(this);
st.start();
}
public void disconnectClientServer(Boolean sendMessage) {
if (communicationSocket == null)
return;
try {
// shut down socket read loop
communicationContinue = false;
disconnectItem.setEnabled(false);
// send notification to other end of socket
if (sendMessage == true)
outStream.println(disconnectString);
// sleep to let read loop shut down
Thread t = Thread.currentThread();
try {
t.sleep(500);
} catch (InterruptedException ie) {
return;
}
outStream.close();
inStream.close();
communicationSocket.close();
} catch (IOException e) {
System.err.println("Stream Read Failed.");
JOptionPane.showMessageDialog(SimpleChat.this, "Disconnection Failed", "SimpleChat", JOptionPane.PLAIN_MESSAGE);
return;
} finally {
communicationSocket = null;
}
}
public void sendData() {
if (communicationSocket != null) {
String data = displayLabel.getText();
outStream.println(data);
}
}
public void getData() {
String inputLine;
try {
while (communicationContinue == true) {
communicationSocket.setSoTimeout(100);
// System.out.println ("Waiting for Connection");
try {
while (((inputLine = inStream.readLine()) != null)) {
System.out.println("From socket: " + inputLine);
if (inputLine.equals(disconnectString)) {
disconnectClientServer(false);
return;
}
displayLabel.setText(inputLine);
}
} catch (SocketTimeoutException ste) {
// System.out.println ("Timeout Occurred");
}
} // end of while loop
System.out.println("communication is false");
} catch (IOException e) {
System.err.println("Stream Read Failed.");
JOptionPane.showMessageDialog(SimpleChat.this, "Input Stream read failed", "SimpleChat",
JOptionPane.PLAIN_MESSAGE);
return;
}
}
}
class ServerThread extends Thread {
private SimpleChat sc;
private JTextField display;
public ServerThread(SimpleChat scParam) {
sc = scParam;
}
public void run() {
ServerSocket connectionSocket = null;
try {
connectionSocket = new ServerSocket(10007);
} catch (IOException e) {
System.err.println("Could not listen on port: 10007.");
JOptionPane.showMessageDialog(sc, "Could not listen on port: 10007", "Server", JOptionPane.PLAIN_MESSAGE);
return;
}
JOptionPane.showMessageDialog(sc, "Server Socket is now activated", "Server", JOptionPane.PLAIN_MESSAGE);
Socket communicationSocket = null;
try {
communicationSocket = connectionSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed.");
JOptionPane.showMessageDialog(sc, "Accept failed", "Server", JOptionPane.PLAIN_MESSAGE);
return;
}
JOptionPane.showMessageDialog(sc, "Comminucation is now activated", "Server", JOptionPane.PLAIN_MESSAGE);
try {
PrintWriter out = new PrintWriter(communicationSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(communicationSocket.getInputStream()));
sc.setCommunicationSocket(communicationSocket);
sc.setOutStream(out);
sc.setInStream(in);
connectionSocket.close();
sc.getData();
} catch (IOException e) {
System.err.println("Accept failed.");
JOptionPane.showMessageDialog(sc, "Creation of Input//Output Streams failed", "Server", JOptionPane.PLAIN_MESSAGE);
return;
}
}
}
class ClientThread extends Thread {
private SimpleChat sc;
public ClientThread(SimpleChat scParam) {
sc = scParam;
}
public void run() {
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
String ipAddress = "127.0.0.1";
try {
echoSocket = new Socket(ipAddress, 10007);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host: " + ipAddress);
JOptionPane.showMessageDialog(sc, "Don't know about host: " + ipAddress, "Client", JOptionPane.PLAIN_MESSAGE);
return;
} catch (IOException e) {
System.err.println("Couldn't get I/O for " + "the connection to: " + ipAddress);
JOptionPane.showMessageDialog(sc, "Couldn't get I/O for the connection to: " + ipAddress, "Client",
JOptionPane.PLAIN_MESSAGE);
return;
}
JOptionPane.showMessageDialog(sc, "Comminucation is now activated", "Client", JOptionPane.PLAIN_MESSAGE);
sc.setCommunicationSocket(echoSocket);
sc.setOutStream(out);
sc.setInStream(in);
sc.getData();
}
}
I suggest you read up on java serialization. There is an example here. Basically, there is built in serialization support. Your class needs to implement Serializable. Then you use ObjectOutputStream and ObjectInputStream to write object.
You would be well advised to use libraries that shield you from the error prone low level socket programming.
For C++ look to Boost (http://www.boost.com) or ACE (http://www.cs.wustl.edu/~schmidt/ACE.html)
For Java I only found a document that talks about the acceptor pattern http://www.hillside.net/plop/plop99/proceedings/Fernandez3/RACPattern.PDF
But I am sure there's an implementation out somewhere
Your on the right track. A chat program is a good place to start learning about sockets.
What you want is to use the ObjectOutputStream and ObjectInputStream classes. You simply have to wrap your input stream / output stream with these filters. ObjectOutputStream has a method writeObject(), and the ObjectInputStream has a corresponding readObject() method.
Most serialization examples show reading and writing objects to a file, but the same can be done using a socket stream. See http://www.acm.org/crossroads/xrds4-2/serial.html
I didn't bother to read through your piles and piles of code, but in general you can't directly send objects over the network. Network communication is just bits and bytes. If you want to send objects, you'll need to serialize them on the sending side, and de-serialize them on the receiving side. There are tons of methods of serializing, eg JSON, XML, or even Java's built-in serialization support (only recommended if both the client and server will always be Java).
You may find this code to be a decent starting point for making your own class. These are two classes I made to somewhat abstract the work needed for TCP and UDP socket protocols:
http://code.google.com/p/hivewars/source/browse/trunk/SocketData.java
http://code.google.com/p/hivewars/source/browse/trunk/UDPSocket.java
Quick dislaimer: These are kind of versions of a feature full class, I just added functionality as I needed it. However, it could help you start.

Categories