* RMI system much more tolerant of bad data now (will display warning in log instead of crashing)
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7040 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
5faa1f08fe
commit
3087235def
@ -43,10 +43,13 @@ import java.io.InputStream;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kirill
|
* @author Kirill Vainer
|
||||||
*/
|
*/
|
||||||
public class AppletHarness extends Applet {
|
public class AppletHarness extends Applet {
|
||||||
|
|
||||||
@ -70,12 +73,26 @@ public class AppletHarness extends Applet {
|
|||||||
|
|
||||||
// load app cfg
|
// load app cfg
|
||||||
if (appCfg != null){
|
if (appCfg != null){
|
||||||
|
InputStream in = null;
|
||||||
try {
|
try {
|
||||||
InputStream in = appCfg.openStream();
|
in = appCfg.openStream();
|
||||||
settings.load(in);
|
settings.load(in);
|
||||||
in.close();
|
in.close();
|
||||||
} catch (IOException ex){
|
} catch (IOException ex){
|
||||||
|
// Called before application has been created ....
|
||||||
|
// Display error message through AWT
|
||||||
|
JOptionPane.showMessageDialog(this, "An error has occured while "
|
||||||
|
+ "loading applet configuration"
|
||||||
|
+ ex.getMessage(),
|
||||||
|
"jME3 Applet",
|
||||||
|
JOptionPane.ERROR_MESSAGE);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
if (in != null)
|
||||||
|
try {
|
||||||
|
in.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,20 +39,20 @@ package com.jme3.network.rmi;
|
|||||||
*
|
*
|
||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
*/
|
*/
|
||||||
class MethodDef {
|
public class MethodDef {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method name
|
* Method name
|
||||||
*/
|
*/
|
||||||
String name;
|
public String name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return type
|
* Return type
|
||||||
*/
|
*/
|
||||||
Class<?> retType;
|
public Class<?> retType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameter types
|
* Parameter types
|
||||||
*/
|
*/
|
||||||
Class<?>[] paramTypes;
|
public Class<?>[] paramTypes;
|
||||||
}
|
}
|
||||||
|
@ -37,33 +37,33 @@ import com.jme3.network.serializing.Serializable;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
class ObjectDef {
|
public class ObjectDef {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The object name, can be null if undefined.
|
* The object name, can be null if undefined.
|
||||||
*/
|
*/
|
||||||
String objectName;
|
public String objectName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object ID
|
* Object ID
|
||||||
*/
|
*/
|
||||||
int objectId;
|
public int objectId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Methods of the implementation on the local client. Set to null
|
* Methods of the implementation on the local client. Set to null
|
||||||
* on remote clients.
|
* on remote clients.
|
||||||
*/
|
*/
|
||||||
Method[] methods;
|
public Method[] methods;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method definitions of the implementation. Set to null on
|
* Method definitions of the implementation. Set to null on
|
||||||
* the local client.
|
* the local client.
|
||||||
*/
|
*/
|
||||||
MethodDef[] methodDefs;
|
public MethodDef[] methodDefs;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
return "ObjectDef[name=" + objectName + ", ID=" + objectId+"]";
|
return "ObjectDef[name=" + objectName + ", objectId=" + objectId+"]";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -42,25 +42,36 @@ import com.jme3.network.serializing.Serializer;
|
|||||||
import com.jme3.util.IntMap;
|
import com.jme3.util.IntMap;
|
||||||
import com.jme3.util.IntMap.Entry;
|
import com.jme3.util.IntMap.Entry;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class ObjectStore implements MessageListener, ConnectionListener {
|
public class ObjectStore implements MessageListener, ConnectionListener {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(ObjectStore.class.getName());
|
||||||
|
|
||||||
private static final class Invocation {
|
private static final class Invocation {
|
||||||
|
|
||||||
Object retVal;
|
Object retVal;
|
||||||
boolean available = false;
|
boolean available = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return "Invocation[" + retVal + "]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Client client;
|
private Client client;
|
||||||
private Server server;
|
private Server server;
|
||||||
|
|
||||||
// Local object ID counter
|
// Local object ID counter
|
||||||
private short objectIdCounter = 0;
|
private volatile short objectIdCounter = 0;
|
||||||
|
|
||||||
// Local invocation ID counter
|
// Local invocation ID counter
|
||||||
private short invocationIdCounter = 0;
|
private volatile short invocationIdCounter = 0;
|
||||||
|
|
||||||
// Invocations waiting ..
|
// Invocations waiting ..
|
||||||
private IntMap<Invocation> pendingInvocations = new IntMap<Invocation>();
|
private IntMap<Invocation> pendingInvocations = new IntMap<Invocation>();
|
||||||
@ -120,10 +131,13 @@ public class ObjectStore implements MessageListener, ConnectionListener {
|
|||||||
RemoteObjectDefMessage defMsg = new RemoteObjectDefMessage();
|
RemoteObjectDefMessage defMsg = new RemoteObjectDefMessage();
|
||||||
defMsg.objects = new ObjectDef[]{ makeObjectDef(localObj) };
|
defMsg.objects = new ObjectDef[]{ makeObjectDef(localObj) };
|
||||||
|
|
||||||
if (client != null)
|
if (client != null) {
|
||||||
client.send(defMsg);
|
client.send(defMsg);
|
||||||
else
|
logger.log(Level.INFO, "Client: Sending {0}", defMsg);
|
||||||
|
} else {
|
||||||
server.broadcast(defMsg);
|
server.broadcast(defMsg);
|
||||||
|
logger.log(Level.INFO, "Server: Sending {0}", defMsg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T getExposedObject(String name, Class<T> type, boolean waitFor) throws InterruptedException{
|
public <T> T getExposedObject(String name, Class<T> type, boolean waitFor) throws InterruptedException{
|
||||||
@ -140,7 +154,6 @@ public class ObjectStore implements MessageListener, ConnectionListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ type }, ro);
|
Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ type }, ro);
|
||||||
ro.loadMethods(type);
|
ro.loadMethods(type);
|
||||||
return (T) proxy;
|
return (T) proxy;
|
||||||
@ -163,14 +176,17 @@ public class ObjectStore implements MessageListener, ConnectionListener {
|
|||||||
if (needReturn){
|
if (needReturn){
|
||||||
call.invocationId = invocationIdCounter++;
|
call.invocationId = invocationIdCounter++;
|
||||||
invoke = new Invocation();
|
invoke = new Invocation();
|
||||||
|
// Note: could cause threading issues if used from multiple threads
|
||||||
pendingInvocations.put(call.invocationId, invoke);
|
pendingInvocations.put(call.invocationId, invoke);
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
if (server != null){
|
if (server != null){
|
||||||
remoteObj.client.send(call);
|
remoteObj.client.send(call);
|
||||||
|
logger.log(Level.INFO, "Server: Sending {0}", call);
|
||||||
}else{
|
}else{
|
||||||
client.send(call);
|
client.send(call);
|
||||||
|
logger.log(Level.INFO, "Client: Sending {0}", call);
|
||||||
}
|
}
|
||||||
} catch (IOException ex){
|
} catch (IOException ex){
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
@ -186,6 +202,7 @@ public class ObjectStore implements MessageListener, ConnectionListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Note: could cause threading issues if used from multiple threads
|
||||||
pendingInvocations.remove(call.invocationId);
|
pendingInvocations.remove(call.invocationId);
|
||||||
return invoke.retVal;
|
return invoke.retVal;
|
||||||
}else{
|
}else{
|
||||||
@ -194,6 +211,9 @@ public class ObjectStore implements MessageListener, ConnectionListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void messageReceived(Message message) {
|
public void messageReceived(Message message) {
|
||||||
|
// Might want to do more strict validation of the data
|
||||||
|
// in the message to prevent crashes
|
||||||
|
|
||||||
if (message instanceof RemoteObjectDefMessage){
|
if (message instanceof RemoteObjectDefMessage){
|
||||||
RemoteObjectDefMessage defMsg = (RemoteObjectDefMessage) message;
|
RemoteObjectDefMessage defMsg = (RemoteObjectDefMessage) message;
|
||||||
|
|
||||||
@ -212,27 +232,38 @@ public class ObjectStore implements MessageListener, ConnectionListener {
|
|||||||
}else if (message instanceof RemoteMethodCallMessage){
|
}else if (message instanceof RemoteMethodCallMessage){
|
||||||
RemoteMethodCallMessage call = (RemoteMethodCallMessage) message;
|
RemoteMethodCallMessage call = (RemoteMethodCallMessage) message;
|
||||||
LocalObject localObj = localObjects.get(call.objectId);
|
LocalObject localObj = localObjects.get(call.objectId);
|
||||||
|
if (localObj == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (call.methodId < 0 || call.methodId >= localObj.methods.length)
|
||||||
|
return;
|
||||||
|
|
||||||
Object obj = localObj.theObject;
|
Object obj = localObj.theObject;
|
||||||
Method method = localObj.methods[call.methodId];
|
Method method = localObj.methods[call.methodId];
|
||||||
Object[] args = call.args;
|
Object[] args = call.args;
|
||||||
Object ret;
|
Object ret = null;
|
||||||
try {
|
try {
|
||||||
ret = method.invoke(obj, args);
|
ret = method.invoke(obj, args);
|
||||||
} catch (Exception ex){
|
} catch (IllegalAccessException ex){
|
||||||
throw new RuntimeException(ex);
|
logger.log(Level.WARNING, "RMI: Error accessing method", ex);
|
||||||
|
} catch (IllegalArgumentException ex){
|
||||||
|
logger.log(Level.WARNING, "RMI: Invalid arguments", ex);
|
||||||
|
} catch (InvocationTargetException ex){
|
||||||
|
logger.log(Level.WARNING, "RMI: Invocation exception", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method.getReturnType() != void.class){
|
if (method.getReturnType() != void.class){
|
||||||
// send return value back
|
// send return value back
|
||||||
RemoteMethodReturnMessage retMsg = new RemoteMethodReturnMessage();
|
RemoteMethodReturnMessage retMsg = new RemoteMethodReturnMessage();
|
||||||
retMsg.invocationID = invocationIdCounter++;
|
retMsg.invocationID = call.invocationId;
|
||||||
retMsg.retVal = ret;
|
retMsg.retVal = ret;
|
||||||
try {
|
try {
|
||||||
if (server != null){
|
if (server != null){
|
||||||
call.getClient().send(retMsg);
|
call.getClient().send(retMsg);
|
||||||
|
logger.log(Level.INFO, "Server: Sending {0}", retMsg);
|
||||||
} else{
|
} else{
|
||||||
client.send(retMsg);
|
client.send(retMsg);
|
||||||
|
logger.log(Level.INFO, "Client: Sending {0}", retMsg);
|
||||||
}
|
}
|
||||||
} catch (IOException ex){
|
} catch (IOException ex){
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
@ -242,7 +273,8 @@ public class ObjectStore implements MessageListener, ConnectionListener {
|
|||||||
RemoteMethodReturnMessage retMsg = (RemoteMethodReturnMessage) message;
|
RemoteMethodReturnMessage retMsg = (RemoteMethodReturnMessage) message;
|
||||||
Invocation invoke = pendingInvocations.get(retMsg.invocationID);
|
Invocation invoke = pendingInvocations.get(retMsg.invocationID);
|
||||||
if (invoke == null){
|
if (invoke == null){
|
||||||
throw new RuntimeException("Cannot find invocation ID: " + retMsg.invocationID);
|
logger.log(Level.WARNING, "Cannot find invocation ID: {0}", retMsg.invocationID);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (invoke){
|
synchronized (invoke){
|
||||||
@ -268,8 +300,10 @@ public class ObjectStore implements MessageListener, ConnectionListener {
|
|||||||
try {
|
try {
|
||||||
if (this.client != null){
|
if (this.client != null){
|
||||||
this.client.send(defMsg);
|
this.client.send(defMsg);
|
||||||
|
logger.log(Level.INFO, "Client: Sending {0}", defMsg);
|
||||||
} else{
|
} else{
|
||||||
client.send(defMsg);
|
client.send(defMsg);
|
||||||
|
logger.log(Level.INFO, "Server: Sending {0}", defMsg);
|
||||||
}
|
}
|
||||||
} catch (IOException ex){
|
} catch (IOException ex){
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
|
@ -41,7 +41,7 @@ import com.jme3.network.serializing.Serializable;
|
|||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
class RemoteMethodCallMessage extends Message {
|
public class RemoteMethodCallMessage extends Message {
|
||||||
|
|
||||||
public RemoteMethodCallMessage(){
|
public RemoteMethodCallMessage(){
|
||||||
super(true);
|
super(true);
|
||||||
@ -50,30 +50,30 @@ class RemoteMethodCallMessage extends Message {
|
|||||||
/**
|
/**
|
||||||
* The object ID on which the call is being made.
|
* The object ID on which the call is being made.
|
||||||
*/
|
*/
|
||||||
int objectId;
|
public int objectId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The method ID used for look-up in the LocalObject.methods array.
|
* The method ID used for look-up in the LocalObject.methods array.
|
||||||
*/
|
*/
|
||||||
short methodId;
|
public short methodId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invocation ID is used to identify a particular call if the calling
|
* Invocation ID is used to identify a particular call if the calling
|
||||||
* client needs the return value of the called RMI method.
|
* client needs the return value of the called RMI method.
|
||||||
* This is set to zero if the method does not return a value.
|
* This is set to zero if the method does not return a value.
|
||||||
*/
|
*/
|
||||||
short invocationId;
|
public short invocationId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arguments of the remote method invocation.
|
* Arguments of the remote method invocation.
|
||||||
*/
|
*/
|
||||||
Object[] args;
|
public Object[] args;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("MethodCall[objectID=").append(objectId).append(", methodID=")
|
sb.append("RemoteMethodCallMessage[objectID=").append(objectId).append(", methodID=")
|
||||||
.append(methodId);
|
.append(methodId);
|
||||||
if (args != null && args.length > 0){
|
if (args != null && args.length > 0){
|
||||||
sb.append(", args={");
|
sb.append(", args={");
|
||||||
|
@ -43,7 +43,7 @@ import com.jme3.network.serializing.Serializable;
|
|||||||
* @author Kirill Vainer.
|
* @author Kirill Vainer.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
class RemoteMethodReturnMessage extends Message {
|
public class RemoteMethodReturnMessage extends Message {
|
||||||
|
|
||||||
public RemoteMethodReturnMessage(){
|
public RemoteMethodReturnMessage(){
|
||||||
super(true);
|
super(true);
|
||||||
@ -52,16 +52,16 @@ class RemoteMethodReturnMessage extends Message {
|
|||||||
/**
|
/**
|
||||||
* Invocation ID that was set in the {@link RemoteMethodCallMessage}.
|
* Invocation ID that was set in the {@link RemoteMethodCallMessage}.
|
||||||
*/
|
*/
|
||||||
short invocationID;
|
public short invocationID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The return value, could be null.
|
* The return value, could be null.
|
||||||
*/
|
*/
|
||||||
Object retVal;
|
public Object retVal;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
return "MethodReturn[ID="+invocationID+", Value="+retVal.toString()+"]";
|
return "RemoteMethodReturnMessage[ID="+invocationID+", Value="+retVal.toString()+"]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,12 +42,23 @@ import com.jme3.network.serializing.Serializable;
|
|||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
class RemoteObjectDefMessage extends Message {
|
public class RemoteObjectDefMessage extends Message {
|
||||||
|
|
||||||
ObjectDef[] objects;
|
public ObjectDef[] objects;
|
||||||
|
|
||||||
public RemoteObjectDefMessage(){
|
public RemoteObjectDefMessage(){
|
||||||
super(true);
|
super(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("RemoteObjectDefMessage[\n");
|
||||||
|
for (ObjectDef def : objects){
|
||||||
|
sb.append("\t").append(def).append("\n");
|
||||||
|
}
|
||||||
|
sb.append("]");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@ import com.jme3.network.serializing.SerializerRegistration;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link RmiSerializer} is responsible for serializing RMI messages
|
* {@link RmiSerializer} is responsible for serializing RMI messages
|
||||||
@ -46,12 +48,17 @@ import java.nio.ByteBuffer;
|
|||||||
*/
|
*/
|
||||||
public class RmiSerializer extends Serializer {
|
public class RmiSerializer extends Serializer {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(RmiSerializer.class.getName());
|
||||||
|
|
||||||
|
// not good for multithread applications
|
||||||
private char[] chrBuf = new char[256];
|
private char[] chrBuf = new char[256];
|
||||||
|
|
||||||
private void writeString(ByteBuffer buffer, String string) throws IOException{
|
private void writeString(ByteBuffer buffer, String string) throws IOException{
|
||||||
int length = string.length();
|
int length = string.length();
|
||||||
if (length > 255){
|
if (length > 255){
|
||||||
throw new IOException("Cannot serialize: "+ string + "\nToo long!");
|
logger.log(Level.WARNING, "The string length exceeds the limit! {0} > 255", length);
|
||||||
|
buffer.put( (byte) 0 );
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.put( (byte) length );
|
buffer.put( (byte) length );
|
||||||
@ -73,9 +80,10 @@ public class RmiSerializer extends Serializer {
|
|||||||
buffer.putShort((short)0);
|
buffer.putShort((short)0);
|
||||||
} else {
|
} else {
|
||||||
SerializerRegistration reg = Serializer.getSerializerRegistration(clazz);
|
SerializerRegistration reg = Serializer.getSerializerRegistration(clazz);
|
||||||
if (reg == null)
|
if (reg == null){
|
||||||
throw new IOException("Unknown class: "+clazz);
|
logger.log(Level.WARNING, "Unknown class: {0}", clazz);
|
||||||
|
throw new IOException(); // prevents message from being serialized
|
||||||
|
}
|
||||||
buffer.putShort(reg.getId());
|
buffer.putShort(reg.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,10 +93,12 @@ public class RmiSerializer extends Serializer {
|
|||||||
if (reg == null){
|
if (reg == null){
|
||||||
// either "void" or unknown val
|
// either "void" or unknown val
|
||||||
short id = buffer.getShort(buffer.position()-2);
|
short id = buffer.getShort(buffer.position()-2);
|
||||||
if (id == 0)
|
if (id == 0){
|
||||||
return void.class;
|
return void.class;
|
||||||
else
|
} else{
|
||||||
throw new IOException("Undefined class ID: " + id);
|
logger.log(Level.WARNING, "Undefined class ID: {0}", id);
|
||||||
|
throw new IOException(); // prevents message from being serialized
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return reg.getType();
|
return reg.getType();
|
||||||
}
|
}
|
||||||
@ -173,6 +183,10 @@ public class RmiSerializer extends Serializer {
|
|||||||
buffer.put((byte)0);
|
buffer.put((byte)0);
|
||||||
}else{
|
}else{
|
||||||
buffer.put((byte)call.args.length);
|
buffer.put((byte)call.args.length);
|
||||||
|
|
||||||
|
// Right now it writes 0 for every null argument
|
||||||
|
// and 1 for every non-null argument followed by the serialized
|
||||||
|
// argument. For the future, using a bit set should be considered.
|
||||||
for (Object obj : call.args){
|
for (Object obj : call.args){
|
||||||
if (obj != null){
|
if (obj != null){
|
||||||
buffer.put((byte)0x01);
|
buffer.put((byte)0x01);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user