[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[news.eclipse.technology.ecf] Re: Don't the Group IDs need to be the same?

Hi John,

John F. Patterson wrote:
I'm confused. You indicate below that one person uses "slewis@xxxxxxxxxx" for the GroupID and the other uses "li-te_cheng@xxxxxxxxxx" for the GroupID. If they don't use the same GroupID, how do they ever get their local proxies ties together.

What am I missing?

My mistake. What I meant was that the two addresses would have to be something like:


"slewis@xxxxxxxxxx"

and "li-te_cheng@xxxxxxxxxx"

assuming that "server.com" was the host of the group (on a known port).

If, for a given provider, other info was necessary, things might look like this:

https://server.com:4444/mygroup
or sip://<whatever sip further requires to identify a session>
or jabber:slewis@xxxxxxxxxx/group1

In general, the syntax of the ID for joinging a group is going to be specific to the provider type. Depending upon the provider implementation, it may even be a provider-specific ID type (i.e. define a new ID type just for the given provider.

Thanks for pointing out this error.

Scott




Scott Lewis wrote:

Hi Li-Te and all,

Here are some comments on Li-Te's chat application.

Li-Te wrote:

(note: newsgroup is acting funny .... seeing double posts. so apologies if this appears twice, or if someone already answered John's question)

Here is my rough understanding of this from what I've read so far in the javadoc and online documentation. Someone say something in if I'm wrong here. Putting in "???" in unknown bits.

--- for user 1

// create a chat container - ignore what kind of protocols, etc for now
ISharedObjectContainer chatLobby =
  SharedObjectContainerFactory.
      makeSharedObjectContainer("chatLobby");


Yes.  This is the first step...to create a container for the chat.

In preference to all of the code you have below, I would design things so that the program would be structured as follows:

// join the group...this connects to some server...using any/all
// authentication required by 'chatLobby'
chatLobby.joinGroup(IDFactory.makeStringID("slewis@xxxxxxxxxx",null);

// Create an ISharedObject that represents me...i.e. has my nickname
Chat chat = new Chat("slewis");

// And add the shared object to the container...this will init the Chat
// instance and allow it to start sending/receiving messages
chatLobby.getSharedObjectManager().addSharedObject(IDFactory.makeStringID("chat"),chat,new Properties(),null);


For a simple chat, this would be all I would need. All the functionality of sending/receiving messages would be implemented in the Chat class. I've attached a copy of the source to this class in this email, and I'll also be checking it in to the org.eclipse.ecf.test plugin later today.

User two would have *exactly the same code* except for

"slewis@xxxxxxxxxx" would be changed to "li-te_cheng@xxxxxxxxxx"
and new Chat("slewis") would be changed to "li-te". The Chat object code itself would also be the same on both/all participants.


There would be other ways to implement this functionality, but I think this is the most straightforward. The basic notion is that the ISharedObject is really responsible for implementing all of the 'chat' functionality (or presence functionality, or file sharing functionality, etc).

Some more comments are interspersed below:

<code deleted>

--- for user 2

// similar process like user 1 (log into a chat lobby) and
// then in the chatLobby listener defined by calling
// chatLobby.addListener(), check if an invitation message
// came through.  the invite should hold chatSessionId so
// user 2 can do something like this

private void joinSession( ID chatSessionId )
{
   ISharedObjectContainer chatSession =
    SharedObjectContainerFactory.
      makeSharedObjectContainer("chatSession");

   // e.g. join info could might be a password if the chat room is
   // protected
   Object    joinInfo = ...; // ???
   chatSession.joinGroup(chatSessionId,joinInfo);
}


Several notes:

In this setup, there is a container for a "lobby", the public space to discover other members. The lobby is where people can send invites, and find out who's online (e.g. buddy list). Shared objects in the lobby are really tokens for user presence : if user1's object is in the lobby, then user1 is "online". Login is done via the join() method. Listing who's online is done by listing what object IDs are in the "lobby" container (after join() is called).


Yes.


The lobby needs a unique ID for all users to connect to. This is done by defining an ID via namespaces. IDFactory.getNamespace(...) would define an appropriate namespace for IDFactory.makeID(...)


Yes.


To start a chat, user1 creates another container for the 1-to-1 chat session. join() here denotes creating a session for 1-to-1 access, so a lot of this hinges upon the Object[] parameter in join()... this doesn't feel quite right to me.


As my example above shows, this isn't strictly necessary. There's no reason to have the container create a new container for this simple chat case. To implement a 'multiple chat groups with a lobby chat' sort of approach it might be helpful to define new containers to represent other chat groups, but it's not necessary for this simple chat


To invite user2, user1 sends a message to user2 in the lobby container via a ISharedObjectContext... not sure how to get one of these context objects. I don't see a ISharedObject.getContext() method.


It's on the ISharedObjectConfig that is passed to the shared object via the 'init' method. ISharedObjectConfig.getContext(). This is explicitly modelled after the ServletConfig/ServletContext relationship.

/And

ISharedContainerObject.getConfig() doesn't return a ISharedObjectConfig which has the needed getContext() method.


No, the ISharedObjectContainer.getConfig() is the config associated with the container (not the config associated with the ISharedObject).


user2 would have to set up a listener in the lobby container for invitation message types, and join the 1-to-1 chat session container by calling join(). The ID of the chat session must be passed along in the invitation message.


Does this sound right?


Well yes, except that I would put most of what you are describing for invitation messages and etc in the implementation of the Chat class. The chat class I've provided simply sends around nickname/message pairs...but an invitation message could easily also be defined/responded to within the Chat class itself as you describe.

Hopefully this helps.

Scott


Li-Te


John F. Patterson wrote:

It would help me if we identified a few use cases and worked them through using the API. The simplest is probably starting a chat. We can worry later about actually using the chat. For now, I just want to understand how it all gets started.

Normally, I think of chat as having three main steps to get it going:

  1. One user initiates a chat session.
  2. Somehow another user becomes informed of the existence of the chat
     (the invite)
  3. The second user joins the chat.

For step 1), I assume that I create a SharedContainer to correspond to the chat session. Then I create a SharedObject that will be used to accomplish the actual communication.
For step 2), I assume I must send the ID of the SharedContainer to the other user. I don't believe the ECF provides an explicit way to do this, but one could be invented on top of it.
For step 3), I assume the second user creates a SharedContainer of the appropriate type (how do they know the type?) and Join the group identified by the ID sent to them. Then somehow, they find the SharedObject.


Do I have this right, as far as it goes? As you can see, I am a little unclear on some of the specifics, particularly on how the SharedObjects come to exist on the second machine. Are they brought into existence upon joining the group? Does the second user learn about them via an event?

I would find it helpful to see the code for this use case.


------------------------------------------------------------------------

package org.eclipse.ecf.test.ui.actions;

import java.io.IOException;

import org.eclipse.ecf.core.ISharedObject;
import org.eclipse.ecf.core.ISharedObjectConfig;
import org.eclipse.ecf.core.ISharedObjectContext;
import org.eclipse.ecf.core.SharedObjectInitException;
import org.eclipse.ecf.core.events.RemoteSharedObjectEvent;
import org.eclipse.ecf.core.identity.ID;
import org.eclipse.ecf.core.util.Event;

public class Chat implements ISharedObject {

   public Chat(String nickname) {
       super();
   }

String nickname;
ISharedObjectConfig config;
public void init(ISharedObjectConfig initData)
throws SharedObjectInitException {
this.config = initData;
}


public ID getID() {
if (config == null) return null;
else return config.getSharedObjectID();
}
public void handleEvent(Event event) {
// This is the code to handle a
if (event instanceof RemoteSharedObjectEvent) {
// We've got an instance of event sent by remote
// We'll assume it's a chat message
RemoteSharedObjectEvent chatEvent = (RemoteSharedObjectEvent) event;
handleChatEvent(chatEvent);
} else System.out.println("ID: "+getID().getName()+" got unknown event: "+event);
}
protected void handleChatEvent(RemoteSharedObjectEvent chatEvent) {
// It's actually an object array...see sendChatToRemote
Object [] data = (Object []) chatEvent.getData();
showChatToUI((String) data[0], (String) data[1]);
}
protected void showChatToUI(String senderNickname, String message) {
System.out.println("Received chat message from: "+senderNickname);
System.out.println("Message: "+message);
}


   // This is method to call to send message to remotes
   protected void sendChatToRemote(String message) {
       ISharedObjectContext ctx = config.getContext();
       Object [] data = new Object[] { nickname, message };
       try {
           // Note that null means to *all* remotes in current container
           ctx.sendMessage(null,data);
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
   public void handleEvents(Event[] events) {
       for(int i=0; i < events.length; i++) {
           handleEvent(events[i]);
       }
   }

   public void dispose(ID containerID) {
       System.out.println("ID:"+getID().getName()+" dispose("+containerID.getName()+")");
       config = null;
   }

   public Object getAdapter(Class clazz) {
       System.out.println("ID:"+getID().getName()+" getAdapter("+clazz.getName()+")");
       return null;
   }

}