Modified the Serializer registration of DisconnectMessage
and ClientRegistrationMessage so that they have fixed IDs and registration-independent implementations. This means that no matter how much the internal auto-registration list changes that a game can still manage the protocol version in a graceful way. Prior to this change, removal of a class registration from Serializers auto-registered list meant that a client->server version mismatch was impossible to detect and handle gracefully. Also, now that it was safe to do so, I removed the auto registration of some odd Java beans classes. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9457 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
516e3065dc
commit
476120616c
@ -33,7 +33,10 @@
|
|||||||
package com.jme3.network.message;
|
package com.jme3.network.message;
|
||||||
|
|
||||||
import com.jme3.network.AbstractMessage;
|
import com.jme3.network.AbstractMessage;
|
||||||
import com.jme3.network.serializing.Serializable;
|
import com.jme3.network.serializing.*;
|
||||||
|
import com.jme3.network.serializing.serializers.StringSerializer;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client registration is a message that contains a unique ID. This ID
|
* Client registration is a message that contains a unique ID. This ID
|
||||||
@ -42,10 +45,13 @@ import com.jme3.network.serializing.Serializable;
|
|||||||
* to couple the TCP and UDP connections together into one 'Client' on the
|
* to couple the TCP and UDP connections together into one 'Client' on the
|
||||||
* server.
|
* server.
|
||||||
*
|
*
|
||||||
* @author Lars Wesselius
|
* @author Lars Wesselius, Paul Speed
|
||||||
*/
|
*/
|
||||||
@Serializable()
|
@Serializable()
|
||||||
public class ClientRegistrationMessage extends AbstractMessage {
|
public class ClientRegistrationMessage extends AbstractMessage {
|
||||||
|
|
||||||
|
public static final short SERIALIZER_ID = -44;
|
||||||
|
|
||||||
private long id;
|
private long id;
|
||||||
private String gameName;
|
private String gameName;
|
||||||
private int version;
|
private int version;
|
||||||
@ -73,4 +79,49 @@ public class ClientRegistrationMessage extends AbstractMessage {
|
|||||||
public int getVersion() {
|
public int getVersion() {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getName() + "[id=" + id + ", gameName=" + gameName + ", version=" + version + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message-specific serializer to avoid compatibility issues
|
||||||
|
* between versions. This serializer is registered to the specific
|
||||||
|
* SERIALIZER_ID which is compatible with previous versions of the
|
||||||
|
* SM serializer registrations... and now will be forever.
|
||||||
|
*/
|
||||||
|
public static class ClientRegistrationSerializer extends Serializer {
|
||||||
|
|
||||||
|
public ClientRegistrationMessage readObject( ByteBuffer data, Class c ) throws IOException {
|
||||||
|
|
||||||
|
// Read the null/non-null marker
|
||||||
|
if (data.get() == 0x0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
ClientRegistrationMessage msg = new ClientRegistrationMessage();
|
||||||
|
|
||||||
|
msg.gameName = StringSerializer.readString(data);
|
||||||
|
msg.id = data.getLong();
|
||||||
|
msg.version = data.getInt();
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeObject(ByteBuffer buffer, Object object) throws IOException {
|
||||||
|
|
||||||
|
// Add the null/non-null marker
|
||||||
|
buffer.put( (byte)(object != null ? 0x1 : 0x0) );
|
||||||
|
if (object == null) {
|
||||||
|
// Nothing left to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientRegistrationMessage msg = (ClientRegistrationMessage)object;
|
||||||
|
StringSerializer.writeString( msg.gameName, buffer );
|
||||||
|
|
||||||
|
buffer.putLong(msg.id);
|
||||||
|
buffer.putInt(msg.version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,15 +33,21 @@
|
|||||||
package com.jme3.network.message;
|
package com.jme3.network.message;
|
||||||
|
|
||||||
import com.jme3.network.AbstractMessage;
|
import com.jme3.network.AbstractMessage;
|
||||||
import com.jme3.network.serializing.Serializable;
|
import com.jme3.network.serializing.*;
|
||||||
|
import com.jme3.network.serializing.serializers.StringSerializer;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a disconnect message.
|
* Represents a disconnect message.
|
||||||
*
|
*
|
||||||
* @author Lars Wesselius
|
* @author Lars Wesselius, Paul Speed
|
||||||
*/
|
*/
|
||||||
@Serializable()
|
@Serializable()
|
||||||
public class DisconnectMessage extends AbstractMessage {
|
public class DisconnectMessage extends AbstractMessage {
|
||||||
|
|
||||||
|
public static final short SERIALIZER_ID = -42;
|
||||||
|
|
||||||
public static final String KICK = "Kick";
|
public static final String KICK = "Kick";
|
||||||
public static final String USER_REQUESTED = "User requested";
|
public static final String USER_REQUESTED = "User requested";
|
||||||
public static final String ERROR = "Error";
|
public static final String ERROR = "Error";
|
||||||
@ -65,4 +71,45 @@ public class DisconnectMessage extends AbstractMessage {
|
|||||||
public void setType(String type) {
|
public void setType(String type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getName() + "[reason=" + reason + ", type=" + type + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message-specific serializer to avoid compatibility issues
|
||||||
|
* between versions. This serializer is registered to the specific
|
||||||
|
* SERIALIZER_ID which is compatible with previous versions of the
|
||||||
|
* SM serializer registrations... and now will be forever.
|
||||||
|
*/
|
||||||
|
public static class DisconnectSerializer extends Serializer {
|
||||||
|
|
||||||
|
public DisconnectMessage readObject( ByteBuffer data, Class c ) throws IOException {
|
||||||
|
|
||||||
|
// Read the null/non-null marker
|
||||||
|
if (data.get() == 0x0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
DisconnectMessage msg = new DisconnectMessage();
|
||||||
|
|
||||||
|
msg.reason = StringSerializer.readString(data);
|
||||||
|
msg.type = StringSerializer.readString(data);
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeObject(ByteBuffer buffer, Object object) throws IOException {
|
||||||
|
|
||||||
|
// Add the null/non-null marker
|
||||||
|
buffer.put( (byte)(object != null ? 0x1 : 0x0) );
|
||||||
|
if (object == null) {
|
||||||
|
// Nothing left to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisconnectMessage msg = (DisconnectMessage)object;
|
||||||
|
StringSerializer.writeString( msg.reason, buffer );
|
||||||
|
StringSerializer.writeString( msg.type, buffer );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,30 +73,20 @@ public abstract class Serializer {
|
|||||||
|
|
||||||
private static boolean strictRegistration = true;
|
private static boolean strictRegistration = true;
|
||||||
|
|
||||||
/****************************************************************
|
|
||||||
****************************************************************
|
|
||||||
****************************************************************
|
|
||||||
|
|
||||||
READ THIS BEFORE CHANGING ANYTHING BELOW
|
|
||||||
|
|
||||||
If a registration is moved or removed before the
|
|
||||||
ClientRegistrationMessage then it screws up the application's
|
|
||||||
ability to gracefully warn users about bad versions.
|
|
||||||
|
|
||||||
There really needs to be a version rolled into the protocol
|
|
||||||
and I intend to do that very soon. In the mean time, don't
|
|
||||||
edit the static registrations without decrementing nextId
|
|
||||||
appropriately.
|
|
||||||
|
|
||||||
Yes, that's how fragile this is. Live and learn.
|
|
||||||
|
|
||||||
****************************************************************
|
|
||||||
****************************************************************
|
|
||||||
****************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
// Registers the classes we already have serializers for.
|
// Registers the classes we already have serializers for.
|
||||||
static {
|
static {
|
||||||
|
|
||||||
|
// Preregister some fixed serializers so that they don't move
|
||||||
|
// if the list below is modified. Automatic ID generation will
|
||||||
|
// skip these IDs.
|
||||||
|
registerClassForId( DisconnectMessage.SERIALIZER_ID, DisconnectMessage.class,
|
||||||
|
new DisconnectMessage.DisconnectSerializer() );
|
||||||
|
registerClassForId( ClientRegistrationMessage.SERIALIZER_ID, ClientRegistrationMessage.class,
|
||||||
|
new ClientRegistrationMessage.ClientRegistrationSerializer() );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
registerClass(boolean.class, new BooleanSerializer());
|
registerClass(boolean.class, new BooleanSerializer());
|
||||||
registerClass(byte.class, new ByteSerializer());
|
registerClass(byte.class, new ByteSerializer());
|
||||||
registerClass(char.class, new CharSerializer());
|
registerClass(char.class, new CharSerializer());
|
||||||
@ -125,8 +115,6 @@ public abstract class Serializer {
|
|||||||
registerClass(AbstractList.class, new CollectionSerializer());
|
registerClass(AbstractList.class, new CollectionSerializer());
|
||||||
registerClass(AbstractSet.class, new CollectionSerializer());
|
registerClass(AbstractSet.class, new CollectionSerializer());
|
||||||
registerClass(ArrayList.class, new CollectionSerializer());
|
registerClass(ArrayList.class, new CollectionSerializer());
|
||||||
registerClass(BeanContextServicesSupport.class, new CollectionSerializer());
|
|
||||||
registerClass(BeanContextSupport.class, new CollectionSerializer());
|
|
||||||
registerClass(HashSet.class, new CollectionSerializer());
|
registerClass(HashSet.class, new CollectionSerializer());
|
||||||
registerClass(LinkedHashSet.class, new CollectionSerializer());
|
registerClass(LinkedHashSet.class, new CollectionSerializer());
|
||||||
registerClass(LinkedList.class, new CollectionSerializer());
|
registerClass(LinkedList.class, new CollectionSerializer());
|
||||||
@ -139,7 +127,6 @@ public abstract class Serializer {
|
|||||||
registerClass(HashMap.class, new MapSerializer());
|
registerClass(HashMap.class, new MapSerializer());
|
||||||
registerClass(Hashtable.class, new MapSerializer());
|
registerClass(Hashtable.class, new MapSerializer());
|
||||||
registerClass(IdentityHashMap.class, new MapSerializer());
|
registerClass(IdentityHashMap.class, new MapSerializer());
|
||||||
//registerClass(java.awt.RenderingHints.class, new MapSerializer());
|
|
||||||
registerClass(TreeMap.class, new MapSerializer());
|
registerClass(TreeMap.class, new MapSerializer());
|
||||||
registerClass(WeakHashMap.class, new MapSerializer());
|
registerClass(WeakHashMap.class, new MapSerializer());
|
||||||
|
|
||||||
@ -147,8 +134,6 @@ public abstract class Serializer {
|
|||||||
registerClass(GZIPCompressedMessage.class, new GZIPSerializer());
|
registerClass(GZIPCompressedMessage.class, new GZIPSerializer());
|
||||||
registerClass(ZIPCompressedMessage.class, new ZIPSerializer());
|
registerClass(ZIPCompressedMessage.class, new ZIPSerializer());
|
||||||
|
|
||||||
registerClass(DisconnectMessage.class);
|
|
||||||
registerClass(ClientRegistrationMessage.class);
|
|
||||||
registerClass(ChannelInfoMessage.class);
|
registerClass(ChannelInfoMessage.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user