Mumrah
|
Posted: May 28, 2010 14:53 by Mumrah
|
|
Hi, I'm actualy working on a reddwarf game center. The user log in to redwarf, populate a list with available games and select the game he wants to play. Our project structure is like this: MainApp ---rds-client ---rds-server ---network-model ---ui Game1 ---network-model ---client-ui ---server-addon Game2 ---network-model ---client-ui ---server-addon .... So what's the problem? When a game is selected, the associated network-model needs to extend the MainApp's network-model (only with clientSession communication) but the root decoder aldready loaded is from MainApp and i can't add another one. How could i generate a RootDecoder aware of others network-model projects in MainApp. Or if you've aldready crossed this kind of problem what's the direction you've chosen? Thanks |
Using multiple JnagSessions based on separatly compiled network interfaces.
Replies: 12 - Last Post: July 23, 2010 01:30
by: Vincent Cantin
by: Vincent Cantin
showing 1 - 13 of 13
Vincent Cantin
|
Posted: May 28, 2010 18:18 by Vincent Cantin
|
|
Hello Mumrah, Your usage of Jnag is pretty uncommon. Jnag compiles code because it supposes that it has all the information about the messages at the compile time, but it doesn't seem to be the case for you. I see 2 possibilities to solve your problem: 1) Compile all at the same time. Pros: no particular issue with Jnag. Cons: no pluggability, which is not what you want. 2) Switch the JnagSessions at runtime once the player choose the game. Once the player choose the game, it sends a message to the server, the server receives it, reply to say that it received it and approve the choice, then in the same task it is selecting a second JnagSession configured with the configuration object of the chosen game - you will have to root the incoming messages to this second session. Remember, you are the one to root the messages in and out, not Jnag, you have a perfect control over it. When the client receives the confirmation from the server, the client is doing the same. Pros: no particular issue with Jnag, and you can compile your projects separatly. Cons: you can't have 2 different JnagSessions on the same communication channel at the same time. This may not be a problem for you, you still can open an additional channel just between your client and the server if you need to have the 2 types of JnagSessions communicating at the same time. Did it answer your question ? |
Mumrah
|
Posted: June 01, 2010 11:20 by Mumrah
|
|
Hi Vincent, It's a great step forward but not enough for my scenario cause i don't want to rewrite functions provided by the main application. I'm actually trying to solve this by developping some kind of jnag-addon. This addon will negociate with the server an id (byte) for each new JnagSession on the same Channel or ClientSession. Then for each message the identifier will be inserted as first byte of the ByteBuffer. The receiver will read the identifier and redirect the remaining bytes to the right JnagSession. Like this i can use Jnag without modifying the code for a 1 byte/message cost I hope i could give news about this soon. EDIT: Ouch!! the server side will be more difficult to adapt... |
Vincent Cantin
|
Posted: June 01, 2010 22:34 by Vincent Cantin
|
|
So if I understand well, you are implementing a small message dispatcher between the main client-server channel and a few instances of the JnagSession. That sounds correct to me so far, and you don't have to modify the implementation of Jnag to reach your goal. Note that what you are doing looks similar to what an implementation of Red Dwarf would do to encode data from different channels into 1 socket. I am wondering if you are not re-inventing the wheel here. |
Mumrah
|
Posted: June 07, 2010 15:13 by Mumrah
|
|
Hi, You are right, i'm re-inventing the wheel. So i've changed my mind to something more simple. Using channels like you said in your previous post but still without switching JnagSession. In fact on the client side multiple JnagSession is not a problem. The problem is on the server I've created 3 classes NamedJnagSessionImpl extends JnagSessionImpl NamedProxyFactoryImpl extends ProxyFactoryImpl NamedSharedIdObjectBinding extends SharedIdObjectBinding NamedJnagSessionImpl class take a String parameter named sessionId and an AbstractConfiguration (like the client side) This sessionId is propagated to NamedProxyFactoryImpl and NamedSharedIdObjectBinding Each binding is done using the sessionId. No static initialization needed anymore Like this i can use multiple JnagSession on the server side. Do you see any problem with this? Changes i've made in jnag-rds : JnagSessionImpl protected sharedIdStoreRef protected sharedIdObjectBinding protected proxyFactory ProxyFactoryImpl protected remoteClassNameToProxyClassRef SharedIdObjectBinding protected idToObjectRef protected objectRefToId Could you change your repository with those protected fields? If you can't, could you create an interface for JnagSessionImpl and use it instead of JnagSessionImpl (Ex: RootDecoder.decodeAndInvoke)? Mumrah |
Vincent Cantin
|
Posted: June 10, 2010 10:59 by Vincent Cantin
|
|
I've changed my mind to something more simple. Using channels like you said in your previous post but still without switching JnagSession. In fact on the client side multiple JnagSession is not a problem. The problem is on the server. Hi, I don't see how using multiple sessions could be a problem on the server. Can you explain more about the problem ? |
Mumrah
|
Posted: June 10, 2010 13:15 by Mumrah
|
|
Hello, In fact using multiple instances of JnagSession is not a problem but using multiple instances of JnagSession with multiple AbstractConfiguration is my problem. The problem lies in JnagSessionImpl.initializeGlobalObjects(AbstractConfiguration configuration). When this static function is used, it initialize the JnagSessionImpl once for all instances. If i need to load a second AbstractConfiguration i will erase the previous one. So i've chosen to give an id to the created JnagSessionImpl, like this i can use multiple AbstractConfiguration. Maybe some code will be better than an english explanation from a french guy. !!Do not forget that this code use protected fields (see previous post)!! NamedJnagSessionImpl
package com.lemoulinstudio.jnag.rds;
import java.io.Serializable;
import java.util.logging.Logger;
import com.sun.sgs.app.AppContext;
import com.sun.sgs.app.ManagedReference;
import com.sun.sgs.app.NameNotBoundException;
public class NamedJnagSessionImpl extends JnagSessionImpl implements Serializable {
private static final long serialVersionUID = 1L;
public static Logger logger = Logger.getLogger(JnagSession.class.getName());
private static String sharedIdStoreBindingName = "NamedJnagSharedIdStore";
private static String configBindingName = "NamedJnagConfig";
private ManagedReference<LocalIdStore> getSharedIdStoreRef(String sessionId) {
String bindingName = sharedIdStoreBindingName + "_" + sessionId;
try {
return AppContext.getDataManager().createReference((LocalIdStore)
AppContext.getDataManager().getBinding(bindingName));
} catch (NameNotBoundException e) {
AppContext.getDataManager().setBinding(bindingName, new SharedIdStore());
return AppContext.getDataManager().createReference((LocalIdStore)
AppContext.getDataManager().getBinding(bindingName));
}
}
private AbstractConfiguration getConfiguration(String sessionId, AbstractConfiguration configuration) {
String bindingName = configBindingName + "_" + sessionId;
try {
return (AbstractConfiguration)AppContext.getDataManager().getBinding(bindingName);
} catch (NameNotBoundException e) {
AppContext.getDataManager().setBinding(bindingName, configuration);
return (AbstractConfiguration)AppContext.getDataManager().getBinding(bindingName);
}
}
/**
* Creates a Jnag session.
*/
public NamedJnagSessionImpl(String sessionId, AbstractConfiguration configuration) {
sharedIdStoreRef = getSharedIdStoreRef(sessionId);
sharedIdObjectBinding = new NamedSharedIdObjectBinding(sessionId);
proxyFactory = new NamedProxyFactoryImpl(sessionId, configuration);
rootDecoder = getConfiguration(sessionId, configuration).getRootDecoder();
}
}
NamedProxyFactoryImpl
package com.lemoulinstudio.jnag.rds;
import com.sun.sgs.app.AppContext;
import com.sun.sgs.app.ManagedReference;
import com.sun.sgs.app.NameNotBoundException;
import com.sun.sgs.app.util.ScalableHashMap;
import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.lemoulinstudio.jnag.common.Remote;
import java.lang.reflect.Constructor;
import java.util.Map;
class NamedProxyFactoryImpl extends ProxyFactoryImpl implements Serializable {
private static final long serialVersionUID = 1L;
private static String remoteClassNameToProxyClassBindingName = "NamedJnagRemoteClassNameToProxyClass";
private ManagedReference<ScalableHashMap<String, Class>> getRemoteClassToProxy(String id, AbstractConfiguration configuration)
{
String bindingName = remoteClassNameToProxyClassBindingName + "_" + id;
try {
return AppContext.getDataManager().createReference(
(ScalableHashMap<String, Class>)
AppContext.getDataManager().getBinding(bindingName));
} catch (NameNotBoundException e) {
ScalableHashMap<String, Class> remoteClassNameToProxyClass = new ScalableHashMap<String, Class>();
for (Map.Entry<Class<? extends Remote>, Class> entry : configuration.getRemoteClassToProxyClass().entrySet())
remoteClassNameToProxyClass.put(entry.getKey().getName(), entry.getValue());
AppContext.getDataManager().setBinding(bindingName, remoteClassNameToProxyClass);
return AppContext.getDataManager().createReference(
(ScalableHashMap<String, Class>)
AppContext.getDataManager().getBinding(bindingName));
}
}
private String sessionId;
public NamedProxyFactoryImpl(String sessionId,AbstractConfiguration configuration) {
this.sessionId = sessionId;
Logger.getLogger(NamedProxyFactoryImpl.class.getName()).log(Level.SEVERE, "Named :"+sessionId);
remoteClassNameToProxyClassRef = getRemoteClassToProxy(sessionId, configuration);
}
@Override
public String toString() {
return "NamedProxyFactoryImpl [sessionId=" + sessionId + "]";
}
}
NamedSharedIdObjectBinding
package com.lemoulinstudio.jnag.rds;
import com.lemoulinstudio.jnag.common.BindToSharedId;
import com.sun.sgs.app.AppContext;
import com.sun.sgs.app.ManagedReference;
import com.sun.sgs.app.NameNotBoundException;
import com.sun.sgs.app.util.ScalableHashMap;
import java.io.Serializable;
import java.util.Map;
/**
*
* @author Vincent Cantin
*/
class NamedSharedIdObjectBinding extends SharedIdObjectBinding implements Serializable {
private static final long serialVersionUID = 1L;
private static String idToObjectRefBindingName = "NamedJnagIdToObjectRef";
private static String objectRefToIdBindingName = "NamedJnagObjectRefToId";
private ManagedReference<Map<Id, ManagedReference<? extends BindToSharedId>>> getIdToObjectRef(String sessionId) {
String bindingName = idToObjectRefBindingName + "_" + sessionId;
try {
return AppContext.getDataManager().createReference((Map<Id, ManagedReference<? extends BindToSharedId>>)
AppContext.getDataManager().getBinding(bindingName));
} catch (NameNotBoundException e) {
AppContext.getDataManager().setBinding(bindingName, new ScalableHashMap<Id, ManagedReference<? extends BindToSharedId>>());
return AppContext.getDataManager().createReference((Map<Id, ManagedReference<? extends BindToSharedId>>)
AppContext.getDataManager().getBinding(bindingName));
}
}
private ManagedReference<Map<ManagedReference<? extends BindToSharedId>, Id>> getObjectRefToId(String sessionId) {
String bindingName = objectRefToIdBindingName + "_" + sessionId;
try {
return AppContext.getDataManager().createReference((Map<ManagedReference<? extends BindToSharedId>, Id>)
AppContext.getDataManager().getBinding(bindingName));
} catch (NameNotBoundException e) {
AppContext.getDataManager().setBinding(bindingName, new ScalableHashMap<ManagedReference<? extends BindToSharedId>, Id>());
return AppContext.getDataManager().createReference((Map<ManagedReference<? extends BindToSharedId>, Id>)
AppContext.getDataManager().getBinding(bindingName));
}
}
private String sessionId;
public NamedSharedIdObjectBinding(String sessionId) {
this.sessionId = sessionId;
idToObjectRef = getIdToObjectRef(sessionId);
objectRefToId = getObjectRefToId(sessionId);
}
}
|
Vincent Cantin
|
Posted: June 10, 2010 15:03 by Vincent Cantin
|
| Your english is good enough, and the verbose code was not necessary here (I wanted to know the problem, not the fix). I will take a look at the static code of the rds (Red Dwarf Server) module and see what I can do. |
Vincent Cantin
|
Posted: June 13, 2010 05:39 by Vincent Cantin
|
|
I updated the source code of the rds module on the mercurial repository. The changeset enable you to use different configurations at the same time. However, I didn't see the need to change my class "SharedIdObjectBinding", please correct me if I am wrong. I also didn't test the changeset deeply, so if you find out that something doesn't work as you expected, let me know. |
Vincent Cantin
|
Posted: June 18, 2010 11:40 by Vincent Cantin
|
|
Allo ya quelqu'un ? Ca serait bien d'avoir du feedback de la part des personnes qui demandent des ameliorations, une fois l'amelioration faite. That would be nice to have feedback, specially after changes are done, from the persons who requested the changes. |
Vincent Cantin
|
Posted: July 23, 2010 01:30 by Vincent Cantin
|
| You're welcome. |
showing 1 - 13 of 13
Replies: 12 - Last Post: July 23, 2010 01:30
by: Vincent Cantin
by: Vincent Cantin







