Link to home
Start Free TrialLog in
Avatar of ashleycoker
ashleycoker

asked on

Using the observable interface

How do I use the observable interface in Java?
part of my program:

while(true)
        {
            //Accept the connection request
            //Create a thread to deal with the Client
            try{
            MessageClientThread client = new MessageClientThread(myServerSocket.accept());
            //state.addObserver(client);
            this.addObserver(client);
            client.start();
            } catch (IOException e){
             System.err.println("Error accepting client connection!");
             System.exit(-1);
            }
        }
    }

as you can see it adds observers to itself, which are threads that implement the observer interface.  The threads receive messages from clients on the network.  when they do this, i want them to tell the server code(above) that they have received a message, so that all the clients can be notified of the change and update themselves with the new message.  Basiclly i am implementing a simple messenger program that when a client sends a message to the server, it is replicated on all other clients connected screens.

How do I call the notifyObservers and pass information between the server program and the client threads?
confused!


Thanks

Ashley :-)
Avatar of TimYates
TimYates
Flag of United Kingdom of Great Britain and Northern Ireland image

Avatar of ashleycoker
ashleycoker

ASKER

so what?  I need an explanation not a web link!! no offence!

basically, i am getting confused here:  the client thread has to notify all the other client threads that it has a new message, via the server main thread??

in these examples the server notifies the clients, but in my implementation one of the clients has to notify the server so that it can notify all the other clients.

How, when you create an object from a procedure, can it let the object that created it know anything apart from in return values?, like with my threads, the clients run in a loop.  How can they talk to the server that created them?

Thanks
Ashley :-)
>  so what?  I need an explanation not a web link!! no offence!

If you click on the links, they both lead to explanations... ;-)

(j/k)

Pass the server through to the thread client (in the constructor)

MessageClientThread client = new MessageClientThread( this, myServerSocket.accept() );

Then, make the server an Observer, and in the client, do:

this.addObserver( server ) ;

then, whenever things change (in the client), you should be able to do:

this.setChanged() ;
this.notifyObservers( "I have changed!" ) ;
(assuming your client is Observable) :-)

Hope this helps!!

Tim
>  the client thread has to notify all the other client threads that it has a new message, via the
>server main thread??

  If the server is register to be an observer then it can observe for events from the client. When you call the method notifyObeservers() in the client then when a change is made you notify all registered observers (the server in your case). On the other hand the server can notify its own observers for changes that occured.
>  the client thread has to notify all the other client threads that it has a new message, via the
>server main thread??

Ahhhh...didn't read this properly...

You can still use my way above, in the server's "update" method, you can just iterate through the list of clients, and notify all of them except for the one that sent the original notification (which will be the first parameter of the update method)

So basically, the server, and the clients have to be both Observers, AND Observable...

With the server Observing all the clients, and each client observing the server...

Tim
This is a problem because my clients are threads which means I would have to extend both the Thread interface and the Observable interface, but this is illigal isn't it?

      public class MessageClientThread extends Thread implements Observer{

       -------

       }

I cant also write 'extends Observable' because it causes a compiler error.  Help!

Ashley :-)
> which means I would have to extend both the Thread interface and the Observable interface, but this is illigal isn't it?

Nope...

Thread is a class...you extend classes

Observer and Observable are interfaces....you implement interfaces :-)

public class MessageClientThread extends Thread implements Observer, Observable {

should be fine...
That doesn't work!
The compiler error is:

     JavaExamples/MessageClientThread.java [18:1] interface expected here

My other class works fine with:

     public class MessageServer extends Observable implements Observer{

Ashley
Ahhhh....Observable is a class...

Observer is an interface...

you can do:

public class MessageClientThread extends Observable, implements Observer, Runnable
{
}
extending runnable means you have to do your threading like this:

public class MessageClientThread extends Observable, implements Observer, Runnable
{
    private Thread runner = null ;

    ....

    public void start()
    {
        if( runner == null )
        {
            runner = new Thread( this ) ;
            runner.start() ;
        }
    }

    public void run()
    {
        while( runner != null )
        {
          ....
        }
    }

    public void stop()
    {
        runner = null ;
    }
}
What is the runnable part, something to do with threads?
Does my class still work the same?  i.e. do i still override the run() method?
ASKER CERTIFIED SOLUTION
Avatar of TimYates
TimYates
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks Tim, this all worked great!

One more quick question if you dont mind, ill give you some more points for it!  My clients need to have their GUI updated in a separate thread that runs constantly checking for messages from the server.  Here is my client code:

public class MessageGUI extends JPanel implements ActionListener{
    JButton sayButton;
    JTextField message;
    JTextArea history;
    MessageClient myClient;
    String received = null;
    /** Creates a new instance of MessageGUI */
    public MessageGUI() {
        myClient = new MessageClient();
       
        sayButton = new JButton("Say");
        message = new JTextField(20);
        history = new JTextArea(10, 20);
       
        history.setEditable(false);
       
        //This works but we are going to use messageClient class
        //as Listerner instead
        sayButton.addActionListener(this);
        //sayButton.addActionListener(myClient);
       
        add(message);
        add(sayButton);
        add(history);
    }
   
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        //Create  frame
        JFrame MessageFrame = new JFrame("Message Client");
        MessageFrame.setContentPane(new MessageGUI());
       
        MessageFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        MessageFrame.pack();
        MessageFrame.setVisible(true);
               
    }
   
    public void actionPerformed(ActionEvent e) {
        //this uses myClient to send messages
        //any waiting here will cause GUI to wait until it is updated
        received = myClient.sendMessage(message.getText());
       
        //This would update the screen with message but is done using another thread
        //history.append(received + '\n');
    }
   
}

How do I implement a thread that can run alongside this code and update the GUI when a new message is received?

Thanks

Ashley :-)
> //This would update the screen with message but is done using another thread

Can't you pass that other thread to this class (in the constructor ?), and call a method on it to update the screen?

Good luck!

Tim