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;
}
}