pool;
-
- /**
- * @param references If true, each appearance of an object in the graph after the first is stored as an integer ordinal.
- * When set to true, {@link MapReferenceResolver} is used. This enables references to the same object and
- * cyclic graphs to be serialized, but typically adds overhead of one byte per object. (should be true)
- *
- * @param registrationRequired If true, an exception is thrown when an unregistered class is encountered.
- *
- * If false, when an unregistered class is encountered, its fully qualified class name will be serialized
- * and the {@link Kryo#addDefaultSerializer(Class, Class) default serializer} for the class used to
- * serialize the object. Subsequent appearances of the class within the same object graph are serialized
- * as an int id.
- *
- * Registered classes are serialized as an int id, avoiding the overhead of serializing the class name,
- * but have the drawback of needing to know the classes to be serialized up front.
- *
- * @param factory Sets the serializer factory to use when no {@link Kryo#addDefaultSerializer(Class, Class) default
- * serializers} match an object's type. Default is {@link ReflectionSerializerFactory} with
- * {@link FieldSerializer}. @see Kryo#newDefaultSerializer(Class)
- *
+ * @param references
+ * If true, each appearance of an object in the graph after the first is stored as an integer ordinal. When set to true,
+ * {@link MapReferenceResolver} is used. This enables references to the same object and cyclic graphs to be serialized,
+ * but typically adds overhead of one byte per object. (should be true)
+ *
+ * @param registrationRequired
+ * If true, an exception is thrown when an unregistered class is encountered.
+ *
+ * If false, when an unregistered class is encountered, its fully qualified class name will be serialized and the {@link
+ * Kryo#addDefaultSerializer(Class, Class) default serializer} for the class used to serialize the object. Subsequent
+ * appearances of the class within the same object graph are serialized as an int id.
+ *
+ * Registered classes are serialized as an int id, avoiding the overhead of serializing the class name, but have the
+ * drawback of needing to know the classes to be serialized up front.
+ *
+ * @param factory
+ * Sets the serializer factory to use when no {@link Kryo#addDefaultSerializer(Class, Class) default serializers} match
+ * an object's type. Default is {@link ReflectionSerializerFactory} with {@link FieldSerializer}. @see
+ * Kryo#newDefaultSerializer(Class)
+ *
*/
public
KryoCryptoSerializationManager(final boolean references, final boolean registrationRequired, final SerializerFactory factory) {
@@ -423,264 +214,193 @@ class KryoCryptoSerializationManager implements CryptoSerializationManager {
// This pool wil also pre-populate, so that we have the hit on startup, instead of on access
// this is also so that our register methods can correctly register with all of the kryo instances
- pool = ObjectPoolFactory.create(new PoolableObject() {
+ kryoThreadLocal = new ThreadLocal() {
@Override
- public
- Kryo create() {
- KryoExtra kryo = new KryoExtra();
+ protected
+ KryoExtra initialValue() {
+ synchronized (KryoCryptoSerializationManager.this) {
+ KryoExtra kryo = new KryoExtra();
- // we HAVE to pre-allocate the KRYOs
- boolean useAsm = !useUnsafeMemory;
+ // we HAVE to pre-allocate the KRYOs
+ boolean useAsm = !useUnsafeMemory;
- kryo.setAsmEnabled(useAsm);
- kryo.setRegistrationRequired(registrationRequired);
+ kryo.setAsmEnabled(useAsm);
+ kryo.setRegistrationRequired(registrationRequired);
- kryo.setReferences(references);
+ kryo.setReferences(references);
- if (factory != null) {
- kryo.setDefaultSerializer(factory);
+ for (Class> clazz : classesToRegister) {
+ kryo.register(clazz);
+ }
+
+ for (ClassSerializer classSerializer : classSerializerToRegister) {
+ kryo.register(classSerializer.clazz, classSerializer.serializer);
+ }
+
+ for (ClassSerializer2 classSerializer : classSerializer2ToRegister) {
+ kryo.register(classSerializer.clazz, classSerializer.serializer, classSerializer.id);
+ }
+
+ if (shouldInitRMI) {
+ kryo.register(Class.class);
+ kryo.register(RmiRegistration.class);
+ kryo.register(InvokeMethod.class, methodSerializer);
+ kryo.register(Object[].class);
+
+ // This has to be PER KRYO,
+ InvocationResultSerializer resultSerializer = new InvocationResultSerializer(kryo);
+ resultSerializer.removeField(OBJECT_ID);
+
+ kryo.register(InvokeMethodResult.class, resultSerializer);
+ kryo.register(InvocationHandler.class, invocationSerializer);
+
+ for (RemoteClass remoteClass : remoteClassToRegister) {
+ kryo.register(remoteClass.implClass, remoteObjectSerializer);
+
+ // After all common registrations, register OtherObjectImpl only on the server using the remote object interface ID.
+ // This causes OtherObjectImpl to be serialized as OtherObject.
+ int otherObjectID = kryo.getRegistration(remoteClass.implClass).getId();
+
+ // this overrides the 'otherObjectID' with the specified class/serializer, so that when we WRITE this ID, the impl is READ
+ kryo.register(remoteClass.ifaceClass, remoteObjectSerializer, otherObjectID);
+
+ // we have to save the fact that we might have overridden methods
+ CachedMethod.registerOverridden(remoteClass.ifaceClass, remoteClass.implClass);
+ }
+ }
+
+ if (factory != null) {
+ kryo.setDefaultSerializer(factory);
+ }
+
+ return kryo;
}
-
- return kryo;
}
- }, capacity);
+ };
}
/**
- * If the class is not registered and {@link Kryo#setRegistrationRequired(boolean)} is false, it is
- * automatically registered using the {@link Kryo#addDefaultSerializer(Class, Class) default serializer}.
+ * If the class is not registered and {@link Kryo#setRegistrationRequired(boolean)} is false, it is automatically registered using the
+ * {@link Kryo#addDefaultSerializer(Class, Class) default serializer}.
*
- * @throws IllegalArgumentException if the class is not registered and {@link Kryo#setRegistrationRequired(boolean)} is true.
+ * @throws IllegalArgumentException if the class is not registered and {@link Kryo#setRegistrationRequired(boolean)} is true.
* @see ClassResolver#getRegistration(Class)
*/
@Override
public synchronized
Registration getRegistration(Class> clazz) {
- Kryo kryo = null;
- Registration r = null;
-
- try {
- kryo = this.pool.take();
- r = kryo.getRegistration(clazz);
- } catch (InterruptedException e) {
- final String msg = "Interrupted during getRegistration()";
- logger.error(msg);
- } finally {
- if (kryo != null) {
- this.pool.release(kryo);
- }
- }
-
- return r;
+ return kryoThreadLocal.get().getRegistration(clazz);
}
/**
- * Registers the class using the lowest, next available integer ID and the
- * {@link Kryo#getDefaultSerializer(Class) default serializer}. If the class
- * is already registered, the existing entry is updated with the new
- * serializer. Registering a primitive also affects the corresponding
- * primitive wrapper.
- *
- * Because the ID assigned is affected by the IDs registered before it, the
- * order classes are registered is important when using this method. The
- * order must be the same at deserialization as it was for serialization.
+ * Registers the class using the lowest, next available integer ID and the {@link Kryo#getDefaultSerializer(Class) default serializer}.
+ * If the class is already registered, the existing entry is updated with the new serializer. Registering a primitive also affects the
+ * corresponding primitive wrapper.
+ *
+ * Because the ID assigned is affected by the IDs registered before it, the order classes are registered is important when using this
+ * method. The order must be the same at deserialization as it was for serialization.
*/
@Override
public synchronized
void register(Class> clazz) {
if (initialized) {
- throw new RuntimeException("Cannot register classes after initialization.");
+ logger.warn("Serialization manager already initialized. Ignoring duplicate register(Class) call.");
}
- Kryo kryo;
- try {
- for (int i = 0; i < capacity; i++) {
- kryo = this.pool.take();
- kryo.register(clazz);
- this.pool.release(kryo);
- }
- } catch (InterruptedException e) {
- throw new RuntimeException("Thread interrupted during kryo pool take/release cycle!", e);
- }
+ classesToRegister.add(clazz);
}
/**
- * Registers the class using the lowest, next available integer ID and the
- * specified serializer. If the class is already registered, the existing
- * entry is updated with the new serializer. Registering a primitive also
- * affects the corresponding primitive wrapper.
- *
- * Because the ID assigned is affected by the IDs registered before it, the
- * order classes are registered is important when using this method. The
- * order must be the same at deserialization as it was for serialization.
+ * Registers the class using the lowest, next available integer ID and the specified serializer. If the class is already registered, the
+ * existing entry is updated with the new serializer. Registering a primitive also affects the corresponding primitive wrapper.
+ *
+ * Because the ID assigned is affected by the IDs registered before it, the order classes are registered is important when using this
+ * method. The order must be the same at deserialization as it was for serialization.
*/
@Override
public synchronized
void register(Class> clazz, Serializer> serializer) {
if (initialized) {
- throw new RuntimeException("Cannot register classes after initialization.");
+ logger.warn("Serialization manager already initialized. Ignoring duplicate register(Class, Serializer) call.");
+ return;
}
- Kryo kryo;
- try {
- for (int i = 0; i < capacity; i++) {
- kryo = this.pool.take();
- kryo.register(clazz, serializer);
- this.pool.release(kryo);
- }
- } catch (InterruptedException e) {
- throw new RuntimeException("Thread interrupted during kryo pool take/release cycle!", e);
- }
+ classSerializerToRegister.add(new ClassSerializer(clazz, serializer));
}
/**
- * Registers the class using the specified ID and serializer. If the ID is
- * already in use by the same type, the old entry is overwritten. If the ID
- * is already in use by a different type, a {@link KryoException} is thrown.
- * Registering a primitive also affects the corresponding primitive wrapper.
- *
+ * Registers the class using the specified ID and serializer. If the ID is already in use by the same type, the old entry is
+ * overwritten. If the ID is already in use by a different type, a {@link KryoException} is thrown. Registering a primitive also affects
+ * the corresponding primitive wrapper.
+ *
* IDs must be the same at deserialization as they were for serialization.
*
- * @param id Must be >= 0. Smaller IDs are serialized more efficiently. IDs
- * 0-8 are used by default for primitive types and String, but
- * these IDs can be repurposed.
+ * @param id Must be >= 0. Smaller IDs are serialized more efficiently. IDs 0-8 are used by default for primitive types and
+ * String, but these IDs can be repurposed.
*/
@Override
public synchronized
void register(Class> clazz, Serializer> serializer, int id) {
if (initialized) {
- throw new RuntimeException("Cannot register classes after initialization.");
+ logger.warn("Serialization manager already initialized. Ignoring duplicate register(Class, Serializer, int) call.");
+ return;
}
- Kryo kryo;
- try {
- for (int i = 0; i < capacity; i++) {
- kryo = this.pool.take();
- kryo.register(clazz, serializer, id);
- this.pool.release(kryo);
- }
- } catch (InterruptedException e) {
- throw new RuntimeException("Thread interrupted during kryo pool take/release cycle!", e);
- }
+ classSerializer2ToRegister.add(new ClassSerializer2(clazz, serializer, id));
}
/**
- * Objects that we want to use RMI with must be accessed via an interface. This method configures the serialization of an
- * implementation to be serialized via the defined interface, as a RemoteObject (ie: proxy object). If the implementation
- * class is ALREADY registered, then it's registration will be overwritten by this one
+ * Objects that we want to use RMI with must be accessed via an interface. This method configures the serialization of an implementation
+ * to be serialized via the defined interface, as a RemoteObject (ie: proxy object). If the implementation class is ALREADY registered,
+ * then it's registration will be overwritten by this one
*
* @param ifaceClass The interface used to access the remote object
- * @param implClass The implementation class of the interface
+ * @param implClass The implementation class of the interface
*/
@Override
public synchronized
void registerRemote(final Class ifaceClass, final Class implClass) {
- register(implClass, new RemoteObjectSerializer());
-
- // After all common registrations, register OtherObjectImpl only on the server using the remote object interface ID.
- // This causes OtherObjectImpl to be serialized as OtherObject.
- int otherObjectID = getRegistration(implClass).getId();
-
- // this overrides the 'otherObjectID' with the specified class/serializer, so that when we WRITE this ID, the impl is READ
- register(ifaceClass, new RemoteObjectSerializer(), otherObjectID);
-
- // we have to save the fact that we might have overridden methods
- CachedMethod.registerOverridden(ifaceClass, implClass);
+ remoteClassToRegister.add(new RemoteClass(ifaceClass, implClass));
}
/**
- * Necessary to register classes for RMI, only called once when the RMI bridge is created.
+ * Necessary to register classes for RMI, only called once if/when the RMI bridge is created.
*/
@Override
public synchronized
void initRmiSerialization() {
if (initialized) {
- // already initialized.
+ logger.warn("Serialization manager already initialized. Ignoring duplicate initRmiSerialization() call.");
return;
}
- InvokeMethodSerializer methodSerializer = new InvokeMethodSerializer();
- Serializer