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?
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 = "" []) 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 = "" 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;
}
}
|