From 9abedf284e5047d5b13ef3df6f230c10d0ab271a Mon Sep 17 00:00:00 2001 From: Paul Speed Date: Sun, 26 Apr 2015 00:09:24 -0400 Subject: [PATCH] Added a message that can be used to compile and send the serializer registry... and then register them on the other end. --- .../SerializerRegistrationsMessage.java | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 jme3-networking/src/main/java/com/jme3/network/message/SerializerRegistrationsMessage.java diff --git a/jme3-networking/src/main/java/com/jme3/network/message/SerializerRegistrationsMessage.java b/jme3-networking/src/main/java/com/jme3/network/message/SerializerRegistrationsMessage.java new file mode 100644 index 000000000..da7f2a7cf --- /dev/null +++ b/jme3-networking/src/main/java/com/jme3/network/message/SerializerRegistrationsMessage.java @@ -0,0 +1,188 @@ +/* + * $Id: SerializerRegistrationsMessage.java 3829 2014-11-24 07:25:43Z pspeed $ + * + * Copyright (c) 2012, Paul Speed + * All rights reserved. + */ + +package com.jme3.network.message; + +import com.jme3.network.AbstractMessage; +import com.jme3.network.serializing.Serializable; +import com.jme3.network.serializing.Serializer; +import com.jme3.network.serializing.SerializerRegistration; +import com.jme3.network.serializing.serializers.FieldSerializer; +import java.util.*; +import java.util.jar.Attributes; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * Holds a compiled set of message registration information that + * can be sent over the wire. The received message can then be + * used to register all of the classes using the same IDs and + * same ordering, etc.. The intent is that the server compiles + * this message once it is sure that all serializable classes have + * been registered. It can then send this to each new client and + * they can use it to register all of the classes without requiring + * exactly reproducing the same calls that the server did to register + * messages. + * + *

Normally, JME recommends that apps have a common utility method + * that they call on both client and server. However, this makes + * pluggable services nearly impossible as some central class has to + * know about all registered serializers. This message implementation + * gets around by only requiring registration on the server.

+ * + * @author Paul Speed + */ +@Serializable +public class SerializerRegistrationsMessage extends AbstractMessage { + + static final Logger log = Logger.getLogger(SerializerRegistrationsMessage.class.getName()); + + public static final Set ignore = new HashSet(); + static { + // We could build this automatically but then we + // risk making a client and server out of date simply because + // their JME versions are out of date. + ignore.add(Boolean.class); + ignore.add(Float.class); + ignore.add(Boolean.class); + ignore.add(Byte.class); + ignore.add(Character.class); + ignore.add(Short.class); + ignore.add(Integer.class); + ignore.add(Long.class); + ignore.add(Float.class); + ignore.add(Double.class); + ignore.add(String.class); + + ignore.add(DisconnectMessage.class); + ignore.add(ClientRegistrationMessage.class); + + ignore.add(Date.class); + ignore.add(AbstractCollection.class); + ignore.add(AbstractList.class); + ignore.add(AbstractSet.class); + ignore.add(ArrayList.class); + ignore.add(HashSet.class); + ignore.add(LinkedHashSet.class); + ignore.add(LinkedList.class); + ignore.add(TreeSet.class); + ignore.add(Vector.class); + ignore.add(AbstractMap.class); + ignore.add(Attributes.class); + ignore.add(HashMap.class); + ignore.add(Hashtable.class); + ignore.add(IdentityHashMap.class); + ignore.add(TreeMap.class); + ignore.add(WeakHashMap.class); + ignore.add(Enum.class); + + ignore.add(GZIPCompressedMessage.class); + ignore.add(ZIPCompressedMessage.class); + + ignore.add(ChannelInfoMessage.class); + + ignore.add(SerializerRegistrationsMessage.class); + ignore.add(SerializerRegistrationsMessage.Registration.class); + } + + public static SerializerRegistrationsMessage INSTANCE; + public static Registration[] compiled; + private static final Serializer fieldSerializer = new FieldSerializer(); + + private Registration[] registrations; + + public SerializerRegistrationsMessage() { + setReliable(true); + } + + public SerializerRegistrationsMessage( Registration... registrations ) { + setReliable(true); + this.registrations = registrations; + } + + public static void compile() { + + // Let's just see what they are here + List list = new ArrayList(); + for( SerializerRegistration reg : Serializer.getSerializerRegistrations() ) { + Class type = reg.getType(); + if( ignore.contains(type) ) + continue; + if( type.isPrimitive() ) + continue; + + list.add(new Registration(reg)); + } + + if( log.isLoggable(Level.FINE) ) { + log.log( Level.FINE, "Number of registered classes:{0}", list.size()); + for( Registration reg : list ) { + log.log( Level.FINE, " {0}", reg); + } + } + compiled = list.toArray(new Registration[list.size()]); + + INSTANCE = new SerializerRegistrationsMessage(compiled); + } + + public void registerAll() { + for( Registration reg : registrations ) { + log.log( Level.INFO, "Registering:{0}", reg); + reg.register(); + } + } + + @Serializable + public static final class Registration { + + private short id; + private String className; + private String serializerClassName; + + public Registration() { + } + + public Registration( SerializerRegistration reg ) { + + this.id = reg.getId(); + this.className = reg.getType().getName(); + if( reg.getSerializer().getClass() != FieldSerializer.class ) { + this.serializerClassName = reg.getSerializer().getClass().getName(); + } + } + + public void register() { + try { + Class type = Class.forName(className); + Serializer serializer; + if( serializerClassName == null ) { + serializer = fieldSerializer; + } else { + Class serializerType = Class.forName(serializerClassName); + serializer = (Serializer)serializerType.newInstance(); + } + SerializerRegistration result = Serializer.registerClassForId(id, type, serializer); + log.log( Level.FINE, " result:{0}", result); + } catch( ClassNotFoundException e ) { + throw new RuntimeException( "Class not found attempting to register:" + this, e ); + } catch( InstantiationException e ) { + throw new RuntimeException( "Error instantiating serializer registering:" + this, e ); + } catch( IllegalAccessException e ) { + throw new RuntimeException( "Error instantiating serializer registering:" + this, e ); + } + } + + @Override + public String toString() { + return "Registration[" + id + " = " + className + ", serializer=" + serializerClassName + "]"; + } + } +} + + +