Issue #595: Pluggable serializers - basic implementation

This commit is contained in:
Debasish Ghosh 2011-06-07 06:36:21 +05:30
parent b600d0cf52
commit 40d1ca6da2
22 changed files with 1071 additions and 480 deletions

View file

@ -4,98 +4,30 @@
package akka.remote
import akka.serialization.{ Serializers, Serializable }
import akka.remote.protocol.RemoteProtocol._
import akka.util._
import akka.serialization.Serialization
import com.google.protobuf.{ Message, ByteString }
object MessageSerializer {
private def SERIALIZER_JAVA: Serializers.Java = Serializers.Java
private def SERIALIZER_JAVA_JSON: Serializers.JavaJSON = Serializers.JavaJSON
private def SERIALIZER_SCALA_JSON: Serializers.ScalaJSON = Serializers.ScalaJSON
private def SERIALIZER_PROTOBUF: Serializers.Protobuf = Serializers.Protobuf
def setClassLoader(cl: ClassLoader) = {
val someCl = Some(cl)
SERIALIZER_JAVA.classLoader = someCl
SERIALIZER_JAVA_JSON.classLoader = someCl
SERIALIZER_SCALA_JSON.classLoader = someCl
def deserialize(messageProtocol: MessageProtocol, classLoader: Option[ClassLoader] = None): AnyRef = {
val clazz = loadManifest(classLoader, messageProtocol)
Serialization.deserialize(messageProtocol.getMessage.toByteArray,
clazz, classLoader).fold(x throw x, o o)
}
def deserialize(messageProtocol: MessageProtocol): Any = {
messageProtocol.getSerializationScheme match {
case SerializationSchemeType.JAVA
unbox(SERIALIZER_JAVA.fromBinary(messageProtocol.getMessage.toByteArray, None))
case SerializationSchemeType.PROTOBUF
val clazz = loadManifest(SERIALIZER_PROTOBUF.classLoader, messageProtocol)
SERIALIZER_PROTOBUF.fromBinary(messageProtocol.getMessage.toByteArray, Some(clazz))
case SerializationSchemeType.SCALA_JSON
val clazz = loadManifest(SERIALIZER_SCALA_JSON.classLoader, messageProtocol)
val renderer = clazz.newInstance.asInstanceOf[Serializable.ScalaJSON[_]]
renderer.fromBytes(messageProtocol.getMessage.toByteArray)
case SerializationSchemeType.JAVA_JSON
val clazz = loadManifest(SERIALIZER_JAVA_JSON.classLoader, messageProtocol)
SERIALIZER_JAVA_JSON.fromBinary(messageProtocol.getMessage.toByteArray, Some(clazz))
}
}
def serialize(message: Any): MessageProtocol = {
def serialize(message: AnyRef): MessageProtocol = {
val builder = MessageProtocol.newBuilder
if (message.isInstanceOf[Message]) {
val serializable = message.asInstanceOf[Message]
builder.setSerializationScheme(SerializationSchemeType.PROTOBUF)
builder.setMessage(ByteString.copyFrom(serializable.toByteArray))
builder.setMessageManifest(ByteString.copyFromUtf8(serializable.getClass.getName))
} else if (message.isInstanceOf[Serializable.ScalaJSON[_]]) {
builder.setSerializationScheme(SerializationSchemeType.SCALA_JSON)
setMessageAndManifest(builder, message.asInstanceOf[Serializable.ScalaJSON[_ <: Any]])
} else if (message.isInstanceOf[Serializable.JavaJSON]) {
builder.setSerializationScheme(SerializationSchemeType.JAVA_JSON)
setMessageAndManifest(builder, message.asInstanceOf[Serializable.JavaJSON])
} else {
// default, e.g. if no protocol used explicitly then use Java serialization
builder.setSerializationScheme(SerializationSchemeType.JAVA)
builder.setMessage(ByteString.copyFrom(SERIALIZER_JAVA.toBinary(box(message))))
}
val bytes = Serialization.serialize(message).fold(x throw x, b b)
builder.setMessage(ByteString.copyFrom(bytes))
builder.setMessageManifest(ByteString.copyFromUtf8(message.getClass.getName))
builder.build
}
private def loadManifest(classLoader: Option[ClassLoader], messageProtocol: MessageProtocol): Class[_] = {
val manifest = messageProtocol.getMessageManifest.toStringUtf8
if (classLoader.isDefined) classLoader.get.loadClass(manifest)
else Class.forName(manifest)
}
private def setMessageAndManifest(builder: MessageProtocol.Builder, serializable: Serializable) = {
builder.setMessage(ByteString.copyFrom(serializable.toBytes))
builder.setMessageManifest(ByteString.copyFromUtf8(serializable.getClass.getName))
}
private def box(value: Any): AnyRef = value match {
case value: Boolean new java.lang.Boolean(value)
case value: Char new java.lang.Character(value)
case value: Short new java.lang.Short(value)
case value: Int new java.lang.Integer(value)
case value: Long new java.lang.Long(value)
case value: Float new java.lang.Float(value)
case value: Double new java.lang.Double(value)
case value: Byte new java.lang.Byte(value)
case value value.asInstanceOf[AnyRef]
}
private def unbox(value: AnyRef): Any = value match {
case value: java.lang.Boolean value.booleanValue
case value: java.lang.Character value.charValue
case value: java.lang.Short value.shortValue
case value: java.lang.Integer value.intValue
case value: java.lang.Long value.longValue
case value: java.lang.Float value.floatValue
case value: java.lang.Double value.doubleValue
case value: java.lang.Byte value.byteValue
case value value
classLoader map (_.loadClass(manifest)) getOrElse (Class.forName(manifest))
}
}