Browse Source

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

PSp..om 13 years ago
parent
commit
476120616c

+ 53 - 2
engine/src/networking/com/jme3/network/message/ClientRegistrationMessage.java

@@ -33,7 +33,10 @@
 package com.jme3.network.message;
 
 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
@@ -42,10 +45,13 @@ import com.jme3.network.serializing.Serializable;
  *  to couple the TCP and UDP connections together into one 'Client' on the
  *  server.
  *
- * @author Lars Wesselius
+ * @author Lars Wesselius, Paul Speed
  */
 @Serializable()
 public class ClientRegistrationMessage extends AbstractMessage {
+
+    public static final short SERIALIZER_ID = -44;
+    
     private long id;
     private String gameName;
     private int version;
@@ -73,4 +79,49 @@ public class ClientRegistrationMessage extends AbstractMessage {
     public int getVersion() {
         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);                    
+        }
+    }
+     
 }

+ 49 - 2
engine/src/networking/com/jme3/network/message/DisconnectMessage.java

@@ -33,15 +33,21 @@
 package com.jme3.network.message;
 
 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.
  *
- * @author Lars Wesselius
+ * @author Lars Wesselius, Paul Speed
  */
 @Serializable()
 public class DisconnectMessage extends AbstractMessage {
+
+    public static final short SERIALIZER_ID = -42;
+
     public static final String KICK = "Kick";
     public static final String USER_REQUESTED = "User requested";
     public static final String ERROR = "Error";
@@ -65,4 +71,45 @@ public class DisconnectMessage extends AbstractMessage {
     public void setType(String 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 );           
+        }
+    }     
 }

+ 12 - 27
engine/src/networking/com/jme3/network/serializing/Serializer.java

@@ -73,30 +73,20 @@ public abstract class Serializer {
 
     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.
     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(byte.class,      new ByteSerializer());
         registerClass(char.class,      new CharSerializer());
@@ -125,8 +115,6 @@ public abstract class Serializer {
         registerClass(AbstractList.class,               new CollectionSerializer());
         registerClass(AbstractSet.class,                new CollectionSerializer());
         registerClass(ArrayList.class,                  new CollectionSerializer());
-        registerClass(BeanContextServicesSupport.class, new CollectionSerializer());
-        registerClass(BeanContextSupport.class,         new CollectionSerializer());
         registerClass(HashSet.class,                    new CollectionSerializer());
         registerClass(LinkedHashSet.class,              new CollectionSerializer());
         registerClass(LinkedList.class,                 new CollectionSerializer());
@@ -139,7 +127,6 @@ public abstract class Serializer {
         registerClass(HashMap.class,                    new MapSerializer());
         registerClass(Hashtable.class,                  new MapSerializer());
         registerClass(IdentityHashMap.class,            new MapSerializer());
-        //registerClass(java.awt.RenderingHints.class,    new MapSerializer());
         registerClass(TreeMap.class,                    new MapSerializer());
         registerClass(WeakHashMap.class,                new MapSerializer());
         
@@ -147,8 +134,6 @@ public abstract class Serializer {
         registerClass(GZIPCompressedMessage.class, new GZIPSerializer());
         registerClass(ZIPCompressedMessage.class, new ZIPSerializer());
 
-        registerClass(DisconnectMessage.class);
-        registerClass(ClientRegistrationMessage.class);
         registerClass(ChannelInfoMessage.class);
     }
     
@@ -186,7 +171,7 @@ public abstract class Serializer {
     }
  
     protected static SerializerRegistration registerClassForId( short id, Class cls, Serializer serializer ) {
-    
+ 
         SerializerRegistration reg = new SerializerRegistration(serializer, cls, id);
 
         idRegistrations.put(id, reg);