Added a message that can be used to compile and

send the serializer registry... and then register
them on the other end.
This commit is contained in:
Paul Speed 2015-04-26 00:09:24 -04:00
parent c9eaeeea12
commit 9abedf284e

View File

@ -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.
*
* <p>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.</p>
*
* @author Paul Speed
*/
@Serializable
public class SerializerRegistrationsMessage extends AbstractMessage {
static final Logger log = Logger.getLogger(SerializerRegistrationsMessage.class.getName());
public static final Set<Class> ignore = new HashSet<Class>();
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<Registration> list = new ArrayList<Registration>();
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 + "]";
}
}
}