views:

134

answers:

2

Hello everyone,

I first need to apologize for my earlier questions. (You can check my profile for them)They seemed to ask more questions than give answers. Hence, I am laying down the actual question that started all them absurd questions.

I am trying to design a chat applet. Till now, I have coded the applet, servlet and communication between the applet and the servlet. The code in the servlet side is such that I was able to establish chatting between clients using the applets, but the code was more like a broadcast all feature, i.e. all clients would be chatting with each other. That was my first objective when I started designing the chat applet. The second step is chatting between only two specific users, much like any other chat application we have. So this was my idea for it:

  1. I create an instance of the servlet that has the 'broadcast-all' code.
  2. I then pass the address of this instance to the respective clients.
  3. 2 client applets use the address to then chat. Technically the code is 'broadcast-all', but since only 2 clients are connected to it, it gives the chatting between two clients feature. Thus, groups of 2 clients have different instances of the same servlet, and each instance handles chatting between two clients at a max.

However, as predicted, the idea didn't materialize!

I tried to create an instance of the servlet but the only solution for that was using sessions on the servlet side, and I don't know how to use this session for later communications.

I now know how to use the request.getSession(). So I set the session for an applet in its param tag and use it for further communications with the servlet. But how do I use this data to establish chatting between two clients? As I wrote earlier, I have the code for broadcast_all chatting as follows:

public class CustomerServlet extends HttpServlet {

public String getNextMessage() {
    // Create a message sink to wait for a new message from the
    // message source.
    return new MessageSink().getNextMessage(source);
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
    ObjectOutputStream dout = new ObjectOutputStream(response.getOutputStream());
    String recMSG = getNextMessage();
    dout.writeObject(recMSG);
    dout.flush();
}

public void broadcastMessage(String message) {
    // Send the message to all the HTTP-connected clients by giving the
    // message to the message source
    source.sendMessage(message);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
    try {
        ObjectInputStream din= new ObjectInputStream(request.getInputStream());
        String message = (String)din.readObject();
        ObjectOutputStream dout = new ObjectOutputStream(response.getOutputStream());
        dout.writeObject("1");
        dout.flush();
        if (message != null) {
            broadcastMessage(message);
        }
        // Set the status code to indicate there will be no response
        response.setStatus(response.SC_NO_CONTENT);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
MessageSource source = new MessageSource();
}

class MessageSource extends Observable {
public void sendMessage(String message) {
    setChanged();
    notifyObservers(message);
}
}
class MessageSink implements Observer {
String message = null;  // set by update() and read by getNextMessage()
// Called by the message source when it gets a new message
synchronized public void update(Observable o, Object arg) {
    // Get the new message
    message = (String)arg;
    // Wake up our waiting thread
    notify();
}
// Gets the next message sent out from the message source
synchronized public String getNextMessage(MessageSource source) {
    // Tell source we want to be told about new messages
    source.addObserver(this);
    // Wait until our update() method receives a message
    while (message == null) {
        try {
            wait();
        } catch (Exception e) {
            System.out.println("Exception has occured! ERR ERR ERR");
        }
    }
    // Tell source to stop telling us about new messages
    source.deleteObserver(this);
    // Now return the message we received
    // But first set the message instance variable to null
    // so update() and getNextMessage() can be called again.
    String messageCopy = message;
    message = null;
    return messageCopy;
}
}

On the applet side, I have a thread that will connect to the servlet above using GET method to get new messages. It uses a while loop, and blocks until it gets a message from the servlet. The main thread communicates with the servlet using POST method whenever the client has entered the message. Currently all clients chat with everyone. I want to use the same methods used above (or if possible any other way) to establish chatting between two clients and two clients only. I could possibly have another thread in the applet to check if any other user wishes to chat with it and then exchange some data so that only those two user chat...

I then tried to modify my broadcast-all code. In that code, I was using classes that implemented Observer and Observable interfaces. So the next idea that I got was:

  1. Create a new object of the Observable class(say class_1). This object be common to 2 clients.
  2. 2 clients that wish to chat will use same object of the class_1.
  3. 2 other clients will use a different object of class_1.

But the problem here lies with the class that implements the Observer interface(say class_2). Since this has observers monitoring the same type of class, namely class_1, how do I establish an observer monitoring one object of class_1 and another observer monitoring another object of the same class class_1 (Because notifyObservers() would notify all the observers and I can't assign a particular observer to a particular object)?

I first decided to ask individual problems, like how to create instances of servlets, using objects of observable and observer and so on in stackoverflow... but I got confused even more. Can anyone give me an idea how to establish chatting between two clients only?(I am using Http and not sockets or RMI).

Regards, Mithun.

P.S. Thanks to all who replied to my previous (absurd) queries. I should have stated the purpose earlier so that you guys could help me better.

+1  A: 

You need to store all connected users in a Map<String, User> in the application scope using ServletContext#setAttribute(). The String denotes the unique user identifier (chat nickname?). You need to store the specific chat User as well in the session scope using HttpSession#setAttribute(). You also need to store the other user in individual chats in a Map<String, User> in the session scope of the users in question. You can obtain the attribute by the getAttribute() method.

This way you know which users are all available and which user is in the current session and with which users it is individually chatting.

BalusC
In Map<string, user>, "string" is name of one client(nickname). What is "user"? Is it the name of the user that "string" is chatting with?
mithun1538
It should be a value object representing the individual client/user in question. It can contain information about the username, ip, other users it is chatting with, history, etc, whatever you like. You can of course also just stick to a `List<String>` with only usernames.
BalusC
ok. Till now I have understood this:1. In applet side, I do the changes that you asked me to in that other "instance of servlet" question2. In servlet side, I note down all the users that are connected. I'll use LIST instead of MAP, and add unique users to the list in the application context. After that I just lose you. Nevertheless, you have given an idea to me w.r.t setting sessions.. I'll work on that. Thanks
mithun1538
There is only one instance of the servlet in application's lifetime. Make use of the application scope to know which users are all available. Make use of the session scope which user is currently requesting the servlet and also which users it is currently all chatting to. You should **never** assign request or session scoped data as instance variable of the servlet. Work inside the `doGet()` or `doPost()` method only.
BalusC
A: 

This is a crude way to do it, but I just couldn't find a feasible solution. What I did was that I made all users connect to the servlet that had the broadcastAll code. Each user would be aware of which other user it is chatting with. Hence, while sending a message, the user would append his name and the name of the user that he is chatting with to the message. Since it is a broadcastAll code, every connected user would receive the message. After receiving the message, the user would parse the message to get the user who sent the message, and the name of the user for whom the message was intended. It would compare these two names with its records - see the statement in bold earlier. If matched it would display the message, else ignore it.

Again, its a crude way to do it and I am sure there are better solution out there.

mithun1538