Issue #595: Pluggable serializers - basic implementation
This commit is contained in:
parent
b600d0cf52
commit
40d1ca6da2
22 changed files with 1071 additions and 480 deletions
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2011 Scalable Solutions AB <http://scalablesolutions.se>
|
||||
*/
|
||||
|
||||
package akka.testing
|
||||
|
||||
import akka.serialization.Serializer
|
||||
import com.google.protobuf.Message
|
||||
import org.codehaus.jackson.map.ObjectMapper
|
||||
import java.io.{ ObjectOutputStream, ByteArrayOutputStream, ObjectInputStream, ByteArrayInputStream }
|
||||
import akka.util.ClassLoaderObjectInputStream
|
||||
import sjson.json._
|
||||
|
||||
class ProtobufSerializer extends Serializer {
|
||||
val ARRAY_OF_BYTE_ARRAY = Array[Class[_]](classOf[Array[Byte]])
|
||||
|
||||
def toBinary(obj: AnyRef): Array[Byte] = {
|
||||
if (!obj.isInstanceOf[Message]) throw new IllegalArgumentException(
|
||||
"Can't serialize a non-protobuf message using protobuf [" + obj + "]")
|
||||
obj.asInstanceOf[Message].toByteArray
|
||||
}
|
||||
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]], classLoader: Option[ClassLoader] = None): AnyRef = {
|
||||
if (!clazz.isDefined) throw new IllegalArgumentException(
|
||||
"Need a protobuf message class to be able to serialize bytes using protobuf")
|
||||
clazz.get.getDeclaredMethod("parseFrom", ARRAY_OF_BYTE_ARRAY: _*).invoke(null, bytes).asInstanceOf[Message]
|
||||
}
|
||||
}
|
||||
object ProtobufSerializer extends ProtobufSerializer
|
||||
|
||||
class JavaJSONSerializer extends Serializer {
|
||||
private val mapper = new ObjectMapper
|
||||
|
||||
def toBinary(obj: AnyRef): Array[Byte] = {
|
||||
val bos = new ByteArrayOutputStream
|
||||
val out = new ObjectOutputStream(bos)
|
||||
mapper.writeValue(out, obj)
|
||||
out.close
|
||||
bos.toByteArray
|
||||
}
|
||||
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]], classLoader: Option[ClassLoader] = None): AnyRef = {
|
||||
if (!clazz.isDefined) throw new IllegalArgumentException(
|
||||
"Can't deserialize JSON to instance if no class is provided")
|
||||
val in =
|
||||
if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes))
|
||||
else new ObjectInputStream(new ByteArrayInputStream(bytes))
|
||||
val obj = mapper.readValue(in, clazz.get).asInstanceOf[AnyRef]
|
||||
in.close
|
||||
obj
|
||||
}
|
||||
}
|
||||
object JavaJSONSerializer extends JavaJSONSerializer
|
||||
|
||||
class SJSONSerializer extends Serializer {
|
||||
|
||||
def toBinary(obj: AnyRef): Array[Byte] =
|
||||
sjson.json.Serializer.SJSON.out(obj)
|
||||
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]], cl: Option[ClassLoader] = None): AnyRef = {
|
||||
if (!clazz.isDefined) throw new IllegalArgumentException(
|
||||
"Can't deserialize JSON to instance if no class is provided")
|
||||
|
||||
import sjson.json.Serializer._
|
||||
val sj = new SJSON with DefaultConstructor { val classLoader = cl }
|
||||
sj.in(bytes, clazz.get.getName)
|
||||
}
|
||||
}
|
||||
object SJSONSerializer extends SJSONSerializer
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2011 Scalable Solutions AB <http://scalablesolutions.se>
|
||||
*/
|
||||
|
||||
package akka.serialization
|
||||
|
||||
import org.scalatest.junit.JUnitSuite
|
||||
import org.junit.Test
|
||||
import akka.serialization.Serialization._
|
||||
import scala.reflect._
|
||||
|
||||
object SerializeSpec {
|
||||
@BeanInfo
|
||||
case class Address(no: String, street: String, city: String, zip: String) { def this() = this("", "", "", "") }
|
||||
@BeanInfo
|
||||
case class Person(name: String, age: Int, address: Address) { def this() = this("", 0, null) }
|
||||
|
||||
case class Record(id: Int, person: Person)
|
||||
}
|
||||
|
||||
class SerializeSpec extends JUnitSuite {
|
||||
import SerializeSpec._
|
||||
|
||||
@Test
|
||||
def shouldSerializeAddress {
|
||||
val addr = Address("120", "Monroe Street", "Santa Clara", "95050")
|
||||
val b = serialize(addr) match {
|
||||
case Left(exception) ⇒ fail(exception)
|
||||
case Right(bytes) ⇒ bytes
|
||||
}
|
||||
deserialize(b.asInstanceOf[Array[Byte]], classOf[Address], None) match {
|
||||
case Left(exception) ⇒ fail(exception)
|
||||
case Right(add) ⇒ assert(add === addr)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
def shouldSerializePerson {
|
||||
val person = Person("debasish ghosh", 25, Address("120", "Monroe Street", "Santa Clara", "95050"))
|
||||
val b = serialize(person) match {
|
||||
case Left(exception) ⇒ fail(exception)
|
||||
case Right(bytes) ⇒ bytes
|
||||
}
|
||||
deserialize(b.asInstanceOf[Array[Byte]], classOf[Person], None) match {
|
||||
case Left(exception) ⇒ fail(exception)
|
||||
case Right(p) ⇒ assert(p === person)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
def shouldSerializeRecordWithDefaultSerializer {
|
||||
val person = Person("debasish ghosh", 25, Address("120", "Monroe Street", "Santa Clara", "95050"))
|
||||
val r = Record(100, person)
|
||||
val b = serialize(r) match {
|
||||
case Left(exception) ⇒ fail(exception)
|
||||
case Right(bytes) ⇒ bytes
|
||||
}
|
||||
deserialize(b.asInstanceOf[Array[Byte]], classOf[Record], None) match {
|
||||
case Left(exception) ⇒ fail(exception)
|
||||
case Right(p) ⇒ assert(p === r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
akka {
|
||||
actor {
|
||||
serializers {
|
||||
java = "akka.serialization.JavaSerializer"
|
||||
proto = "akka.testing.ProtobufSerializer"
|
||||
sjson = "akka.testing.SJSONSerializer"
|
||||
default = "akka.serialization.JavaSerializer"
|
||||
}
|
||||
|
||||
bindings {
|
||||
java = ["akka.serialization.SerializeSpec$Address", "akka.serialization.MyJavaSerializableActor", "akka.serialization.MyStatelessActorWithMessagesInMailbox", "akka.serialization.MyActorWithProtobufMessagesInMailbox"]
|
||||
sjson = ["akka.serialization.SerializeSpec$Person"]
|
||||
proto = ["com.google.protobuf.Message", "akka.actor.ProtobufProtocol$MyMessage"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -397,23 +397,28 @@ object Actor extends ListenerManagement {
|
|||
"] for serialization of actor [" + address +
|
||||
"] since " + reason)
|
||||
|
||||
val serializer: Serializer = serializerClassName match {
|
||||
case null | "" | Format.`defaultSerializerName` ⇒ Format.Default
|
||||
case specialSerializer ⇒
|
||||
ReflectiveAccess.getClassFor(specialSerializer) match {
|
||||
case Right(clazz) ⇒
|
||||
clazz.newInstance match {
|
||||
case s: Serializer ⇒ s
|
||||
case other ⇒ serializerErrorDueTo("class must be of type [akka.serialization.Serializer]")
|
||||
}
|
||||
case Left(exception) ⇒
|
||||
val cause = exception match {
|
||||
case i: InvocationTargetException ⇒ i.getTargetException
|
||||
case _ ⇒ exception
|
||||
}
|
||||
serializerErrorDueTo(cause.toString)
|
||||
}
|
||||
}
|
||||
val serializer: Serializer =
|
||||
akka.serialization.Serialization.getSerializer(this.getClass).fold(x ⇒ serializerErrorDueTo(x.toString), s ⇒ s)
|
||||
|
||||
/**
|
||||
* val serializer: Serializer = serializerClassName match {
|
||||
* case null | "" | Format.`defaultSerializerName` ⇒ Format.Default
|
||||
* case specialSerializer ⇒
|
||||
* ReflectiveAccess.getClassFor(specialSerializer) match {
|
||||
* case Right(clazz) ⇒
|
||||
* clazz.newInstance match {
|
||||
* case s: Serializer ⇒ s
|
||||
* case other ⇒ serializerErrorDueTo("class must be of type [akka.serialization.Serializer]")
|
||||
* }
|
||||
* case Left(exception) ⇒
|
||||
* val cause = exception match {
|
||||
* case i: InvocationTargetException ⇒ i.getTargetException
|
||||
* case _ ⇒ exception
|
||||
* }
|
||||
* serializerErrorDueTo(cause.toString)
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
val isStateful = state match {
|
||||
case _: Stateless | Stateless ⇒ false
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import akka.actor.DeploymentConfig._
|
|||
import akka.config.{ ConfigurationException, Config }
|
||||
import akka.routing.RouterType
|
||||
import akka.util.ReflectiveAccess._
|
||||
import akka.serialization.Format
|
||||
import akka.serialization._
|
||||
import akka.AkkaException
|
||||
|
||||
/**
|
||||
|
|
@ -31,7 +31,7 @@ object DeploymentConfig {
|
|||
case class Deploy(
|
||||
address: String,
|
||||
routing: Routing = Direct,
|
||||
format: String = Format.defaultSerializerName,
|
||||
format: String = Serializer.defaultSerializerName, // Format.defaultSerializerName,
|
||||
scope: Scope = Local)
|
||||
|
||||
// --------------------------------
|
||||
|
|
@ -263,7 +263,7 @@ object Deployer {
|
|||
// --------------------------------
|
||||
val addressPath = "akka.actor.deployment." + address
|
||||
Config.config.getSection(addressPath) match {
|
||||
case None ⇒ Some(Deploy(address, Direct, Format.defaultSerializerName, Local))
|
||||
case None ⇒ Some(Deploy(address, Direct, Serializer.defaultSerializerName, Local))
|
||||
case Some(addressConfig) ⇒
|
||||
|
||||
// --------------------------------
|
||||
|
|
@ -290,14 +290,14 @@ object Deployer {
|
|||
// --------------------------------
|
||||
// akka.actor.deployment.<address>.format
|
||||
// --------------------------------
|
||||
val format = addressConfig.getString("format", Format.defaultSerializerName)
|
||||
val format = addressConfig.getString("format", Serializer.defaultSerializerName)
|
||||
|
||||
// --------------------------------
|
||||
// akka.actor.deployment.<address>.clustered
|
||||
// --------------------------------
|
||||
addressConfig.getSection("clustered") match {
|
||||
case None ⇒
|
||||
Some(Deploy(address, router, Format.defaultSerializerName, Local)) // deploy locally
|
||||
Some(Deploy(address, router, Serializer.defaultSerializerName, Local)) // deploy locally
|
||||
|
||||
case Some(clusteredConfig) ⇒
|
||||
|
||||
|
|
|
|||
|
|
@ -119,4 +119,10 @@ object Config {
|
|||
|
||||
val startTime = System.currentTimeMillis
|
||||
def uptime = (System.currentTimeMillis - startTime) / 1000
|
||||
|
||||
val serializers = config.getSection("akka.actor.serializers").map(_.map).getOrElse(Map("default" -> "akka.serialization.JavaSerializer"))
|
||||
val bindings = config.getSection("akka.actor.bindings")
|
||||
.map(_.map)
|
||||
.map(m ⇒ Map() ++ m.map { case (k, v: List[String]) ⇒ Map() ++ v.map((_, k)) }.flatten)
|
||||
val serializerMap = bindings.map(m ⇒ m.map { case (k, v: String) ⇒ (k, serializers(v)) }).getOrElse(Map())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,44 +10,44 @@ import java.io.{ ObjectOutputStream, ByteArrayOutputStream, ObjectInputStream, B
|
|||
|
||||
/**
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
* trait Serializer extends scala.Serializable {
|
||||
* @volatile
|
||||
* var classLoader: Option[ClassLoader] = None
|
||||
* def deepClone(obj: AnyRef): AnyRef = fromBinary(toBinary(obj), Some(obj.getClass))
|
||||
*
|
||||
* def toBinary(obj: AnyRef): Array[Byte]
|
||||
* def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef
|
||||
* }
|
||||
*/
|
||||
trait Serializer extends scala.Serializable {
|
||||
@volatile
|
||||
var classLoader: Option[ClassLoader] = None
|
||||
def deepClone(obj: AnyRef): AnyRef = fromBinary(toBinary(obj), Some(obj.getClass))
|
||||
|
||||
def toBinary(obj: AnyRef): Array[Byte]
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* object Format {
|
||||
* implicit object Default extends Serializer {
|
||||
* import java.io.{ ObjectOutputStream, ByteArrayOutputStream, ObjectInputStream, ByteArrayInputStream }
|
||||
* //import org.apache.commons.io.input.ClassLoaderObjectInputStream
|
||||
*
|
||||
* def toBinary(obj: AnyRef): Array[Byte] = {
|
||||
* val bos = new ByteArrayOutputStream
|
||||
* val out = new ObjectOutputStream(bos)
|
||||
* out.writeObject(obj)
|
||||
* out.close()
|
||||
* bos.toByteArray
|
||||
* }
|
||||
*
|
||||
* def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]], classLoader: Option[ClassLoader] = None): AnyRef = {
|
||||
* val in =
|
||||
* //if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes)) else
|
||||
* new ObjectInputStream(new ByteArrayInputStream(bytes))
|
||||
* val obj = in.readObject
|
||||
* in.close()
|
||||
* obj
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* val defaultSerializerName = Default.getClass.getName
|
||||
* }
|
||||
*/
|
||||
object Format {
|
||||
implicit object Default extends Serializer {
|
||||
import java.io.{ ObjectOutputStream, ByteArrayOutputStream, ObjectInputStream, ByteArrayInputStream }
|
||||
//import org.apache.commons.io.input.ClassLoaderObjectInputStream
|
||||
|
||||
def toBinary(obj: AnyRef): Array[Byte] = {
|
||||
val bos = new ByteArrayOutputStream
|
||||
val out = new ObjectOutputStream(bos)
|
||||
out.writeObject(obj)
|
||||
out.close()
|
||||
bos.toByteArray
|
||||
}
|
||||
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
|
||||
val in =
|
||||
//if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes)) else
|
||||
new ObjectInputStream(new ByteArrayInputStream(bytes))
|
||||
val obj = in.readObject
|
||||
in.close()
|
||||
obj
|
||||
}
|
||||
}
|
||||
|
||||
val defaultSerializerName = Default.getClass.getName
|
||||
}
|
||||
|
||||
trait FromBinary[T <: Actor] {
|
||||
def fromBinary(bytes: Array[Byte], act: T): T
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
package akka.serialization
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009-2011 Scalable Solutions AB <http://scalablesolutions.se>
|
||||
*/
|
||||
|
||||
import akka.util.ReflectiveAccess._
|
||||
import akka.config.Config
|
||||
import akka.config.Config._
|
||||
import akka.actor.{ ActorRef, Actor }
|
||||
|
||||
object Serialization {
|
||||
case class NoSerializerFoundException(m: String) extends Exception(m)
|
||||
|
||||
def serialize(o: AnyRef): Either[Exception, Array[Byte]] =
|
||||
getSerializer(o.getClass)
|
||||
.fold((ex) ⇒ Left(ex),
|
||||
(ser) ⇒ Right(ser.toBinary(o)))
|
||||
|
||||
def deserialize(bytes: Array[Byte], clazz: Class[_],
|
||||
classLoader: Option[ClassLoader]): Either[Exception, AnyRef] =
|
||||
getSerializer(clazz)
|
||||
.fold((ex) ⇒ Left(ex),
|
||||
(ser) ⇒ Right(ser.fromBinary(bytes, Some(clazz), classLoader)))
|
||||
|
||||
def getSerializer(clazz: Class[_]): Either[Exception, Serializer] = {
|
||||
Config.serializerMap.get(clazz.getName) match {
|
||||
case Some(serializerName: String) ⇒
|
||||
getClassFor(serializerName) match {
|
||||
case Right(serializer) ⇒ {
|
||||
Right(serializer.newInstance.asInstanceOf[Serializer])
|
||||
}
|
||||
case Left(exception) ⇒ Left(exception)
|
||||
}
|
||||
case _ ⇒
|
||||
getDefaultSerializer match {
|
||||
case Some(s: Serializer) ⇒ Right(s)
|
||||
case None ⇒ Left(new Exception("No default serializer found for " + clazz))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def getDefaultSerializer = {
|
||||
Config.serializers.get("default") match {
|
||||
case Some(ser: String) ⇒
|
||||
getClassFor(ser) match {
|
||||
case Right(srializer) ⇒ {
|
||||
Some(srializer.newInstance.asInstanceOf[Serializer])
|
||||
}
|
||||
case Left(exception) ⇒ None
|
||||
}
|
||||
case None ⇒ None
|
||||
}
|
||||
}
|
||||
|
||||
private def getSerializerInstanceForBestMatchClass(configMap: collection.mutable.Map[String, String], cl: Class[_]) = {
|
||||
configMap
|
||||
.find {
|
||||
case (clazzName, ser) ⇒
|
||||
getClassFor(clazzName) match {
|
||||
case Right(clazz) ⇒
|
||||
clazz.isAssignableFrom(cl)
|
||||
case _ ⇒ false
|
||||
}
|
||||
}
|
||||
.map {
|
||||
case (_, ser) ⇒
|
||||
getClassFor(ser) match {
|
||||
case Right(s) ⇒
|
||||
val instance = s.newInstance.asInstanceOf[Serializer]
|
||||
Right(instance)
|
||||
case _ ⇒ Left(new Exception("Error instantiating " + ser))
|
||||
}
|
||||
}.getOrElse(Left(NoSerializerFoundException("No mapping serializer found for " + cl)))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package akka.serialization
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009-2011 Scalable Solutions AB <http://scalablesolutions.se>
|
||||
*/
|
||||
|
||||
import java.io.{ ObjectOutputStream, ByteArrayOutputStream, ObjectInputStream, ByteArrayInputStream }
|
||||
import akka.util.ClassLoaderObjectInputStream
|
||||
import akka.actor.ActorRef
|
||||
|
||||
trait Serializer extends scala.Serializable {
|
||||
def toBinary(o: AnyRef): Array[Byte]
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]] = None, classLoader: Option[ClassLoader] = None): AnyRef
|
||||
}
|
||||
|
||||
class JavaSerializer extends Serializer {
|
||||
def toBinary(o: AnyRef): Array[Byte] = {
|
||||
val bos = new ByteArrayOutputStream
|
||||
val out = new ObjectOutputStream(bos)
|
||||
out.writeObject(o)
|
||||
out.close()
|
||||
bos.toByteArray
|
||||
}
|
||||
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]] = None,
|
||||
classLoader: Option[ClassLoader] = None): AnyRef = {
|
||||
val in =
|
||||
if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes)) else
|
||||
new ObjectInputStream(new ByteArrayInputStream(bytes))
|
||||
val obj = in.readObject
|
||||
in.close()
|
||||
obj
|
||||
}
|
||||
}
|
||||
|
||||
object JavaSerializer extends JavaSerializer
|
||||
object Serializer {
|
||||
val defaultSerializerName = JavaSerializer.getClass.getName
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2011 Scalable Solutions AB <http://scalablesolutions.se>
|
||||
*/
|
||||
|
||||
package akka.util
|
||||
|
||||
import java.io.{ InputStream, ObjectInputStream, ObjectStreamClass }
|
||||
|
||||
class ClassLoaderObjectInputStream(classLoader: ClassLoader, is: InputStream) extends ObjectInputStream(is) {
|
||||
override protected def resolveClass(objectStreamClass: ObjectStreamClass): Class[_] = {
|
||||
Class.forName(objectStreamClass.getName, false, classLoader) match {
|
||||
case null ⇒ super.resolveClass(objectStreamClass)
|
||||
case clazz ⇒ clazz
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ import akka.routing.RouterType
|
|||
import akka.config.{ Config, Supervision }
|
||||
import Supervision._
|
||||
import Config._
|
||||
import akka.serialization.{ Format, Serializers, Serializer, Compression }
|
||||
import akka.serialization.{ Format, Serializer, Compression }
|
||||
import Compression.LZF
|
||||
import akka.AkkaException
|
||||
|
||||
|
|
@ -524,7 +524,7 @@ class DefaultClusterNode private[akka] (
|
|||
* with the actor passed in as argument. You can use this to save off snapshots of the actor to a highly
|
||||
* available durable store.
|
||||
*/
|
||||
def store(actorRef: ActorRef, replicationFactor: Int, serializeMailbox: Boolean, format: Serializer): ClusterNode = if (isConnected.isOn) {
|
||||
def store(actorRef: ActorRef, replicationFactor: Int, serializeMailbox: Boolean): ClusterNode = if (isConnected.isOn) {
|
||||
|
||||
import akka.serialization.ActorSerialization._
|
||||
|
||||
|
|
@ -535,8 +535,8 @@ class DefaultClusterNode private[akka] (
|
|||
EventHandler.debug(this,
|
||||
"Storing actor [%s] with UUID [%s] in cluster".format(actorRef.address, uuid))
|
||||
|
||||
val actorBytes = if (shouldCompressData) LZF.compress(toBinary(actorRef, serializeMailbox)(format))
|
||||
else toBinary(actorRef)(format)
|
||||
val actorBytes = if (shouldCompressData) LZF.compress(toBinary(actorRef, serializeMailbox))
|
||||
else toBinary(actorRef)
|
||||
val actorRegistryPath = actorRegistryPathFor(uuid)
|
||||
|
||||
// create UUID -> Array[Byte] for actor registry
|
||||
|
|
@ -668,7 +668,7 @@ class DefaultClusterNode private[akka] (
|
|||
* Checks out an actor for use on this node, e.g. checked out as a 'LocalActorRef' but it makes it available
|
||||
* for remote access through lookup by its UUID.
|
||||
*/
|
||||
def use[T <: Actor](actorAddress: String, format: Serializer): Option[LocalActorRef] = if (isConnected.isOn) {
|
||||
def use[T <: Actor](actorAddress: String): Option[LocalActorRef] = if (isConnected.isOn) {
|
||||
|
||||
import akka.serialization.ActorSerialization._
|
||||
|
||||
|
|
@ -699,7 +699,7 @@ class DefaultClusterNode private[akka] (
|
|||
locallyCheckedOutActors += (uuid -> bytes)
|
||||
// FIXME switch to ReplicatedActorRef here
|
||||
// val actor = new ReplicatedActorRef(fromBinary[T](bytes, remoteServerAddress)(format))
|
||||
val actor = fromBinary[T](bytes, remoteServerAddress)(format)
|
||||
val actor = fromBinary[T](bytes, remoteServerAddress)
|
||||
// remoteService.register(UUID_PREFIX + uuid, actor) // FIXME is Actor.remote.register(UUID, ..) correct here?
|
||||
actor.start()
|
||||
actor.asInstanceOf[LocalActorRef]
|
||||
|
|
|
|||
|
|
@ -3280,32 +3280,23 @@ public final class RemoteProtocol {
|
|||
return akka.remote.protocol.RemoteProtocol.internal_static_MessageProtocol_fieldAccessorTable;
|
||||
}
|
||||
|
||||
// required .SerializationSchemeType serializationScheme = 1;
|
||||
public static final int SERIALIZATIONSCHEME_FIELD_NUMBER = 1;
|
||||
private boolean hasSerializationScheme;
|
||||
private akka.remote.protocol.RemoteProtocol.SerializationSchemeType serializationScheme_;
|
||||
public boolean hasSerializationScheme() { return hasSerializationScheme; }
|
||||
public akka.remote.protocol.RemoteProtocol.SerializationSchemeType getSerializationScheme() { return serializationScheme_; }
|
||||
|
||||
// required bytes message = 2;
|
||||
public static final int MESSAGE_FIELD_NUMBER = 2;
|
||||
// required bytes message = 1;
|
||||
public static final int MESSAGE_FIELD_NUMBER = 1;
|
||||
private boolean hasMessage;
|
||||
private com.google.protobuf.ByteString message_ = com.google.protobuf.ByteString.EMPTY;
|
||||
public boolean hasMessage() { return hasMessage; }
|
||||
public com.google.protobuf.ByteString getMessage() { return message_; }
|
||||
|
||||
// optional bytes messageManifest = 3;
|
||||
public static final int MESSAGEMANIFEST_FIELD_NUMBER = 3;
|
||||
// optional bytes messageManifest = 2;
|
||||
public static final int MESSAGEMANIFEST_FIELD_NUMBER = 2;
|
||||
private boolean hasMessageManifest;
|
||||
private com.google.protobuf.ByteString messageManifest_ = com.google.protobuf.ByteString.EMPTY;
|
||||
public boolean hasMessageManifest() { return hasMessageManifest; }
|
||||
public com.google.protobuf.ByteString getMessageManifest() { return messageManifest_; }
|
||||
|
||||
private void initFields() {
|
||||
serializationScheme_ = akka.remote.protocol.RemoteProtocol.SerializationSchemeType.JAVA;
|
||||
}
|
||||
public final boolean isInitialized() {
|
||||
if (!hasSerializationScheme) return false;
|
||||
if (!hasMessage) return false;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3313,14 +3304,11 @@ public final class RemoteProtocol {
|
|||
public void writeTo(com.google.protobuf.CodedOutputStream output)
|
||||
throws java.io.IOException {
|
||||
getSerializedSize();
|
||||
if (hasSerializationScheme()) {
|
||||
output.writeEnum(1, getSerializationScheme().getNumber());
|
||||
}
|
||||
if (hasMessage()) {
|
||||
output.writeBytes(2, getMessage());
|
||||
output.writeBytes(1, getMessage());
|
||||
}
|
||||
if (hasMessageManifest()) {
|
||||
output.writeBytes(3, getMessageManifest());
|
||||
output.writeBytes(2, getMessageManifest());
|
||||
}
|
||||
getUnknownFields().writeTo(output);
|
||||
}
|
||||
|
|
@ -3331,17 +3319,13 @@ public final class RemoteProtocol {
|
|||
if (size != -1) return size;
|
||||
|
||||
size = 0;
|
||||
if (hasSerializationScheme()) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeEnumSize(1, getSerializationScheme().getNumber());
|
||||
}
|
||||
if (hasMessage()) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeBytesSize(2, getMessage());
|
||||
.computeBytesSize(1, getMessage());
|
||||
}
|
||||
if (hasMessageManifest()) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeBytesSize(3, getMessageManifest());
|
||||
.computeBytesSize(2, getMessageManifest());
|
||||
}
|
||||
size += getUnknownFields().getSerializedSize();
|
||||
memoizedSerializedSize = size;
|
||||
|
|
@ -3501,9 +3485,6 @@ public final class RemoteProtocol {
|
|||
|
||||
public Builder mergeFrom(akka.remote.protocol.RemoteProtocol.MessageProtocol other) {
|
||||
if (other == akka.remote.protocol.RemoteProtocol.MessageProtocol.getDefaultInstance()) return this;
|
||||
if (other.hasSerializationScheme()) {
|
||||
setSerializationScheme(other.getSerializationScheme());
|
||||
}
|
||||
if (other.hasMessage()) {
|
||||
setMessage(other.getMessage());
|
||||
}
|
||||
|
|
@ -3535,21 +3516,11 @@ public final class RemoteProtocol {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
int rawValue = input.readEnum();
|
||||
akka.remote.protocol.RemoteProtocol.SerializationSchemeType value = akka.remote.protocol.RemoteProtocol.SerializationSchemeType.valueOf(rawValue);
|
||||
if (value == null) {
|
||||
unknownFields.mergeVarintField(1, rawValue);
|
||||
} else {
|
||||
setSerializationScheme(value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
case 10: {
|
||||
setMessage(input.readBytes());
|
||||
break;
|
||||
}
|
||||
case 26: {
|
||||
case 18: {
|
||||
setMessageManifest(input.readBytes());
|
||||
break;
|
||||
}
|
||||
|
|
@ -3558,28 +3529,7 @@ public final class RemoteProtocol {
|
|||
}
|
||||
|
||||
|
||||
// required .SerializationSchemeType serializationScheme = 1;
|
||||
public boolean hasSerializationScheme() {
|
||||
return result.hasSerializationScheme();
|
||||
}
|
||||
public akka.remote.protocol.RemoteProtocol.SerializationSchemeType getSerializationScheme() {
|
||||
return result.getSerializationScheme();
|
||||
}
|
||||
public Builder setSerializationScheme(akka.remote.protocol.RemoteProtocol.SerializationSchemeType value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
result.hasSerializationScheme = true;
|
||||
result.serializationScheme_ = value;
|
||||
return this;
|
||||
}
|
||||
public Builder clearSerializationScheme() {
|
||||
result.hasSerializationScheme = false;
|
||||
result.serializationScheme_ = akka.remote.protocol.RemoteProtocol.SerializationSchemeType.JAVA;
|
||||
return this;
|
||||
}
|
||||
|
||||
// required bytes message = 2;
|
||||
// required bytes message = 1;
|
||||
public boolean hasMessage() {
|
||||
return result.hasMessage();
|
||||
}
|
||||
|
|
@ -3600,7 +3550,7 @@ public final class RemoteProtocol {
|
|||
return this;
|
||||
}
|
||||
|
||||
// optional bytes messageManifest = 3;
|
||||
// optional bytes messageManifest = 2;
|
||||
public boolean hasMessageManifest() {
|
||||
return result.hasMessageManifest();
|
||||
}
|
||||
|
|
@ -5736,23 +5686,22 @@ public final class RemoteProtocol {
|
|||
"RemoteMessageProtocol\"g\n\037SerializedTyped" +
|
||||
"ActorRefProtocol\022-\n\010actorRef\030\001 \002(\0132\033.Ser" +
|
||||
"ializedActorRefProtocol\022\025\n\rinterfaceName" +
|
||||
"\030\002 \002(\t\"r\n\017MessageProtocol\0225\n\023serializati" +
|
||||
"onScheme\030\001 \002(\0162\030.SerializationSchemeType" +
|
||||
"\022\017\n\007message\030\002 \002(\014\022\027\n\017messageManifest\030\003 \001" +
|
||||
"(\014\"R\n\021ActorInfoProtocol\022\033\n\004uuid\030\001 \002(\0132\r.",
|
||||
"UuidProtocol\022\017\n\007timeout\030\002 \002(\004\022\017\n\007address" +
|
||||
"\030\003 \001(\t\")\n\014UuidProtocol\022\014\n\004high\030\001 \002(\004\022\013\n\003" +
|
||||
"low\030\002 \002(\004\"3\n\025MetadataEntryProtocol\022\013\n\003ke" +
|
||||
"y\030\001 \002(\t\022\r\n\005value\030\002 \002(\014\"6\n\021LifeCycleProto" +
|
||||
"col\022!\n\tlifeCycle\030\001 \002(\0162\016.LifeCycleType\"1" +
|
||||
"\n\017AddressProtocol\022\020\n\010hostname\030\001 \002(\t\022\014\n\004p" +
|
||||
"ort\030\002 \002(\r\"7\n\021ExceptionProtocol\022\021\n\tclassn" +
|
||||
"ame\030\001 \002(\t\022\017\n\007message\030\002 \002(\t*(\n\013CommandTyp" +
|
||||
"e\022\013\n\007CONNECT\020\001\022\014\n\010SHUTDOWN\020\002*]\n\027Serializ" +
|
||||
"ationSchemeType\022\010\n\004JAVA\020\001\022\013\n\007SBINARY\020\002\022\016",
|
||||
"\n\nSCALA_JSON\020\003\022\r\n\tJAVA_JSON\020\004\022\014\n\010PROTOBU" +
|
||||
"F\020\005*-\n\rLifeCycleType\022\r\n\tPERMANENT\020\001\022\r\n\tT" +
|
||||
"EMPORARY\020\002B\030\n\024akka.remote.protocolH\001"
|
||||
"\030\002 \002(\t\";\n\017MessageProtocol\022\017\n\007message\030\001 \002" +
|
||||
"(\014\022\027\n\017messageManifest\030\002 \001(\014\"R\n\021ActorInfo" +
|
||||
"Protocol\022\033\n\004uuid\030\001 \002(\0132\r.UuidProtocol\022\017\n" +
|
||||
"\007timeout\030\002 \002(\004\022\017\n\007address\030\003 \001(\t\")\n\014UuidP",
|
||||
"rotocol\022\014\n\004high\030\001 \002(\004\022\013\n\003low\030\002 \002(\004\"3\n\025Me" +
|
||||
"tadataEntryProtocol\022\013\n\003key\030\001 \002(\t\022\r\n\005valu" +
|
||||
"e\030\002 \002(\014\"6\n\021LifeCycleProtocol\022!\n\tlifeCycl" +
|
||||
"e\030\001 \002(\0162\016.LifeCycleType\"1\n\017AddressProtoc" +
|
||||
"ol\022\020\n\010hostname\030\001 \002(\t\022\014\n\004port\030\002 \002(\r\"7\n\021Ex" +
|
||||
"ceptionProtocol\022\021\n\tclassname\030\001 \002(\t\022\017\n\007me" +
|
||||
"ssage\030\002 \002(\t*(\n\013CommandType\022\013\n\007CONNECT\020\001\022" +
|
||||
"\014\n\010SHUTDOWN\020\002*]\n\027SerializationSchemeType" +
|
||||
"\022\010\n\004JAVA\020\001\022\013\n\007SBINARY\020\002\022\016\n\nSCALA_JSON\020\003\022" +
|
||||
"\r\n\tJAVA_JSON\020\004\022\014\n\010PROTOBUF\020\005*-\n\rLifeCycl",
|
||||
"eType\022\r\n\tPERMANENT\020\001\022\r\n\tTEMPORARY\020\002B\030\n\024a" +
|
||||
"kka.remote.protocolH\001"
|
||||
};
|
||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
||||
|
|
@ -5812,7 +5761,7 @@ public final class RemoteProtocol {
|
|||
internal_static_MessageProtocol_fieldAccessorTable = new
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_MessageProtocol_descriptor,
|
||||
new java.lang.String[] { "SerializationScheme", "Message", "MessageManifest", },
|
||||
new java.lang.String[] { "Message", "MessageManifest", },
|
||||
akka.remote.protocol.RemoteProtocol.MessageProtocol.class,
|
||||
akka.remote.protocol.RemoteProtocol.MessageProtocol.Builder.class);
|
||||
internal_static_ActorInfoProtocol_descriptor =
|
||||
|
|
|
|||
|
|
@ -89,9 +89,8 @@ message SerializedTypedActorRefProtocol {
|
|||
* Defines a message.
|
||||
*/
|
||||
message MessageProtocol {
|
||||
required SerializationSchemeType serializationScheme = 1;
|
||||
required bytes message = 2;
|
||||
optional bytes messageManifest = 3;
|
||||
required bytes message = 1;
|
||||
optional bytes messageManifest = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ trait NettyRemoteClientModule extends RemoteClientModule { self: ListenerManagem
|
|||
|
||||
private[akka] def withClientFor[T](
|
||||
address: InetSocketAddress, loader: Option[ClassLoader])(fun: RemoteClient ⇒ T): T = {
|
||||
loader.foreach(MessageSerializer.setClassLoader(_))
|
||||
// loader.foreach(MessageSerializer.setClassLoader(_))
|
||||
val key = Address(address)
|
||||
lock.readLock.lock
|
||||
try {
|
||||
|
|
@ -804,7 +804,7 @@ class RemoteServerHandler(
|
|||
val server: NettyRemoteServerModule) extends SimpleChannelUpstreamHandler {
|
||||
import RemoteServerSettings._
|
||||
|
||||
applicationLoader.foreach(MessageSerializer.setClassLoader(_)) //TODO: REVISIT: THIS FEELS A BIT DODGY
|
||||
// applicationLoader.foreach(MessageSerializer.setClassLoader(_)) //TODO: REVISIT: THIS FEELS A BIT DODGY
|
||||
|
||||
val sessionActors = new ChannelLocal[ConcurrentHashMap[String, ActorRef]]()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,90 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2011 Scalable Solutions AB <http://scalablesolutions.se>
|
||||
*/
|
||||
|
||||
package akka.serialization
|
||||
|
||||
import org.codehaus.jackson.map.ObjectMapper
|
||||
|
||||
import com.google.protobuf.Message
|
||||
|
||||
import reflect.Manifest
|
||||
|
||||
import java.io.{ StringWriter, ByteArrayOutputStream, ObjectOutputStream }
|
||||
|
||||
import sjson.json.{ Serializer ⇒ SJSONSerializer }
|
||||
|
||||
/**
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
trait Serializable {
|
||||
def toBytes: Array[Byte]
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialization protocols.
|
||||
*
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
object Serializable {
|
||||
|
||||
/**
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
trait JSON extends Serializable {
|
||||
def toJSON: String
|
||||
}
|
||||
|
||||
/**
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
abstract class JavaJSON extends JSON {
|
||||
|
||||
def toJSON: String = {
|
||||
val out = new StringWriter
|
||||
val mapper = new ObjectMapper
|
||||
mapper.writeValue(out, this)
|
||||
out.close
|
||||
out.toString
|
||||
}
|
||||
|
||||
def toBytes: Array[Byte] = {
|
||||
val bos = new ByteArrayOutputStream
|
||||
val out = new ObjectOutputStream(bos)
|
||||
val mapper = new ObjectMapper
|
||||
mapper.writeValue(out, this)
|
||||
out.close
|
||||
bos.toByteArray
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* case class Address(street: String, city: String, zip: String)
|
||||
* extends ScalaJSON[Address] {
|
||||
*
|
||||
* implicit val AddressFormat: Format[Address] =
|
||||
* asProduct3("street", "city", "zip")(Address)(Address.unapply(_).get)
|
||||
*
|
||||
* import dispatch.json._
|
||||
* import sjson.json._
|
||||
* import sjson.json.JsonSerialization._
|
||||
*
|
||||
* def toJSON: String = JsValue.toJson(tojson(this))
|
||||
* def toBytes: Array[Byte] = tobinary(this)
|
||||
* def fromBytes(bytes: Array[Byte]): Address = frombinary[Address](bytes)
|
||||
* def fromJSON(js: String): Address = fromjson[Address](Js(js))
|
||||
* }
|
||||
*
|
||||
* val a = Address(...)
|
||||
* val js = tojson(a)
|
||||
* val add = fromjson[Address](js)
|
||||
*
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
trait ScalaJSON[T] extends JSON {
|
||||
def toJSON: String
|
||||
def fromJSON(js: String): T
|
||||
def toBytes: Array[Byte]
|
||||
def fromBytes(bytes: Array[Byte]): T
|
||||
}
|
||||
}
|
||||
|
|
@ -23,27 +23,27 @@ import akka.remote.{ RemoteClientSettings, MessageSerializer }
|
|||
* Module for local actor serialization.
|
||||
*/
|
||||
object ActorSerialization {
|
||||
implicit val defaultSerializer = Format.Default
|
||||
implicit val defaultSerializer = akka.serialization.JavaSerializer // Format.Default
|
||||
|
||||
def fromBinary[T <: Actor](bytes: Array[Byte], homeAddress: InetSocketAddress)(implicit format: Serializer): ActorRef =
|
||||
fromBinaryToLocalActorRef(bytes, Some(homeAddress), format)
|
||||
def fromBinary[T <: Actor](bytes: Array[Byte], homeAddress: InetSocketAddress): ActorRef =
|
||||
fromBinaryToLocalActorRef(bytes, Some(homeAddress))
|
||||
|
||||
def fromBinary[T <: Actor](bytes: Array[Byte])(implicit format: Serializer): ActorRef =
|
||||
fromBinaryToLocalActorRef(bytes, None, format)
|
||||
def fromBinary[T <: Actor](bytes: Array[Byte]): ActorRef =
|
||||
fromBinaryToLocalActorRef(bytes, None)
|
||||
|
||||
def toBinary[T <: Actor](a: ActorRef, serializeMailBox: Boolean = true)(implicit format: Serializer): Array[Byte] =
|
||||
toSerializedActorRefProtocol(a, format, serializeMailBox).toByteArray
|
||||
def toBinary[T <: Actor](a: ActorRef, serializeMailBox: Boolean = true): Array[Byte] =
|
||||
toSerializedActorRefProtocol(a, serializeMailBox).toByteArray
|
||||
|
||||
// wrapper for implicits to be used by Java
|
||||
def fromBinaryJ[T <: Actor](bytes: Array[Byte], format: Serializer): ActorRef =
|
||||
fromBinary(bytes)(format)
|
||||
def fromBinaryJ[T <: Actor](bytes: Array[Byte]): ActorRef =
|
||||
fromBinary(bytes)
|
||||
|
||||
// wrapper for implicits to be used by Java
|
||||
def toBinaryJ[T <: Actor](a: ActorRef, format: Serializer, srlMailBox: Boolean = true): Array[Byte] =
|
||||
toBinary(a, srlMailBox)(format)
|
||||
def toBinaryJ[T <: Actor](a: ActorRef, srlMailBox: Boolean = true): Array[Byte] =
|
||||
toBinary(a, srlMailBox)
|
||||
|
||||
private[akka] def toSerializedActorRefProtocol[T <: Actor](
|
||||
actorRef: ActorRef, format: Serializer, serializeMailBox: Boolean = true): SerializedActorRefProtocol = {
|
||||
actorRef: ActorRef, serializeMailBox: Boolean = true): SerializedActorRefProtocol = {
|
||||
val lifeCycleProtocol: Option[LifeCycleProtocol] = {
|
||||
actorRef.lifeCycle match {
|
||||
case Permanent ⇒ Some(LifeCycleProtocol.newBuilder.setLifeCycle(LifeCycleType.PERMANENT).build)
|
||||
|
|
@ -84,23 +84,28 @@ object ActorSerialization {
|
|||
}
|
||||
|
||||
actorRef.receiveTimeout.foreach(builder.setReceiveTimeout(_))
|
||||
builder.setActorInstance(ByteString.copyFrom(format.toBinary(actorRef.actor.asInstanceOf[T])))
|
||||
// builder.setActorInstance(ByteString.copyFrom(format.toBinary(actorRef.actor.asInstanceOf[T])))
|
||||
Serialization.serialize(actorRef.actor.asInstanceOf[T]) match {
|
||||
case Right(bytes) ⇒ builder.setActorInstance(ByteString.copyFrom(bytes))
|
||||
case Left(exception) ⇒ throw new Exception("Error serializing : " + actorRef.actor.getClass.getName)
|
||||
}
|
||||
|
||||
lifeCycleProtocol.foreach(builder.setLifeCycle(_))
|
||||
actorRef.supervisor.foreach(s ⇒ builder.setSupervisor(RemoteActorSerialization.toRemoteActorRefProtocol(s)))
|
||||
if (!actorRef.hotswap.isEmpty) builder.setHotswapStack(ByteString.copyFrom(Serializers.Java.toBinary(actorRef.hotswap)))
|
||||
// if (!actorRef.hotswap.isEmpty) builder.setHotswapStack(ByteString.copyFrom(Serializers.Java.toBinary(actorRef.hotswap)))
|
||||
if (!actorRef.hotswap.isEmpty) builder.setHotswapStack(ByteString.copyFrom(akka.serialization.JavaSerializer.toBinary(actorRef.hotswap)))
|
||||
builder.build
|
||||
}
|
||||
|
||||
private def fromBinaryToLocalActorRef[T <: Actor](
|
||||
bytes: Array[Byte],
|
||||
homeAddress: Option[InetSocketAddress],
|
||||
format: Serializer): ActorRef = {
|
||||
homeAddress: Option[InetSocketAddress]): ActorRef = {
|
||||
val builder = SerializedActorRefProtocol.newBuilder.mergeFrom(bytes)
|
||||
fromProtobufToLocalActorRef(builder.build, format, None)
|
||||
fromProtobufToLocalActorRef(builder.build, None)
|
||||
}
|
||||
|
||||
private[akka] def fromProtobufToLocalActorRef[T <: Actor](
|
||||
protocol: SerializedActorRefProtocol, format: Serializer, loader: Option[ClassLoader]): ActorRef = {
|
||||
protocol: SerializedActorRefProtocol, loader: Option[ClassLoader]): ActorRef = {
|
||||
|
||||
val lifeCycle =
|
||||
if (protocol.hasLifeCycle) {
|
||||
|
|
@ -117,9 +122,13 @@ object ActorSerialization {
|
|||
|
||||
val hotswap =
|
||||
try {
|
||||
format
|
||||
.fromBinary(protocol.getHotswapStack.toByteArray, Some(classOf[Stack[PartialFunction[Any, Unit]]]))
|
||||
.asInstanceOf[Stack[PartialFunction[Any, Unit]]]
|
||||
Serialization.deserialize(protocol.getHotswapStack.toByteArray, classOf[Stack[PartialFunction[Any, Unit]]], loader) match {
|
||||
case Right(r) ⇒ r.asInstanceOf[Stack[PartialFunction[Any, Unit]]]
|
||||
case Left(ex) ⇒ throw new Exception("Cannot de-serialize hotswapstack")
|
||||
}
|
||||
// format
|
||||
// .fromBinary(protocol.getHotswapStack.toByteArray, Some(classOf[Stack[PartialFunction[Any, Unit]]]))
|
||||
// .asInstanceOf[Stack[PartialFunction[Any, Unit]]]
|
||||
} catch {
|
||||
case e: Exception ⇒ Stack[PartialFunction[Any, Unit]]()
|
||||
}
|
||||
|
|
@ -129,7 +138,11 @@ object ActorSerialization {
|
|||
val factory = () ⇒ {
|
||||
val actorClass = classLoader.loadClass(protocol.getActorClassname)
|
||||
try {
|
||||
format.fromBinary(protocol.getActorInstance.toByteArray, Some(actorClass)).asInstanceOf[Actor]
|
||||
Serialization.deserialize(protocol.getActorInstance.toByteArray, actorClass, loader) match {
|
||||
case Right(r) ⇒ r.asInstanceOf[Actor]
|
||||
case Left(ex) ⇒ throw new Exception("Cannot de-serialize : " + actorClass)
|
||||
}
|
||||
// format.fromBinary(protocol.getActorInstance.toByteArray, Some(actorClass)).asInstanceOf[Actor]
|
||||
} catch {
|
||||
case e: Exception ⇒ actorClass.newInstance.asInstanceOf[Actor]
|
||||
}
|
||||
|
|
@ -146,11 +159,7 @@ object ActorSerialization {
|
|||
factory)
|
||||
|
||||
val messages = protocol.getMessagesList.toArray.toList.asInstanceOf[List[RemoteMessageProtocol]]
|
||||
messages.foreach(message ⇒ ar ! MessageSerializer.deserialize(message.getMessage))
|
||||
|
||||
//if (format.isInstanceOf[SerializerBasedActorFormat[_]] == false)
|
||||
// format.fromBinary(protocol.getActorInstance.toByteArray, ar.actor.asInstanceOf[T])
|
||||
//ar
|
||||
messages.foreach(message ⇒ ar ! MessageSerializer.deserialize(message.getMessage, Some(classLoader)))
|
||||
ar
|
||||
}
|
||||
}
|
||||
|
|
@ -174,7 +183,7 @@ object RemoteActorSerialization {
|
|||
*/
|
||||
private[akka] def fromProtobufToRemoteActorRef(protocol: RemoteActorRefProtocol, loader: Option[ClassLoader]): ActorRef = {
|
||||
RemoteActorRef(
|
||||
Serializers.Java.fromBinary(protocol.getInetSocketAddress.toByteArray, Some(classOf[InetSocketAddress])).asInstanceOf[InetSocketAddress],
|
||||
JavaSerializer.fromBinary(protocol.getInetSocketAddress.toByteArray, Some(classOf[InetSocketAddress]), loader).asInstanceOf[InetSocketAddress],
|
||||
protocol.getAddress,
|
||||
protocol.getTimeout,
|
||||
loader)
|
||||
|
|
@ -194,7 +203,7 @@ object RemoteActorSerialization {
|
|||
ReflectiveAccess.RemoteModule.configDefaultAddress
|
||||
}
|
||||
RemoteActorRefProtocol.newBuilder
|
||||
.setInetSocketAddress(ByteString.copyFrom(Serializers.Java.toBinary(remoteAddress)))
|
||||
.setInetSocketAddress(ByteString.copyFrom(JavaSerializer.toBinary(remoteAddress)))
|
||||
.setAddress(actor.address)
|
||||
.setTimeout(actor.timeout)
|
||||
.build
|
||||
|
|
@ -230,7 +239,7 @@ object RemoteActorSerialization {
|
|||
|
||||
message match {
|
||||
case Right(message) ⇒
|
||||
messageBuilder.setMessage(MessageSerializer.serialize(message))
|
||||
messageBuilder.setMessage(MessageSerializer.serialize(message.asInstanceOf[AnyRef]))
|
||||
case Left(exception) ⇒
|
||||
messageBuilder.setException(ExceptionProtocol.newBuilder
|
||||
.setClassname(exception.getClass.getName)
|
||||
|
|
|
|||
|
|
@ -1,149 +1,39 @@
|
|||
package akka.serialization
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009-2011 Scalable Solutions AB <http://scalablesolutions.se>
|
||||
*/
|
||||
|
||||
package akka.serialization
|
||||
|
||||
import java.io.{ ObjectOutputStream, ByteArrayOutputStream, ObjectInputStream, ByteArrayInputStream }
|
||||
import akka.util.ClassLoaderObjectInputStream
|
||||
import akka.actor.ActorRef
|
||||
|
||||
import org.apache.commons.io.input.ClassLoaderObjectInputStream
|
||||
|
||||
import com.google.protobuf.Message
|
||||
|
||||
import org.codehaus.jackson.map.ObjectMapper
|
||||
|
||||
import sjson.json.{ Serializer ⇒ SJSONSerializer }
|
||||
|
||||
// For Java API
|
||||
class SerializerFactory {
|
||||
import Serializers._
|
||||
def getJava: Java.type = Java
|
||||
def getJavaJSON: JavaJSON.type = JavaJSON
|
||||
def getScalaJSON: ScalaJSON.type = ScalaJSON
|
||||
def getProtobuf: Protobuf.type = Protobuf
|
||||
trait Serializer extends scala.Serializable {
|
||||
def toBinary(o: AnyRef): Array[Byte]
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]] = None, classLoader: Option[ClassLoader] = None): AnyRef
|
||||
}
|
||||
|
||||
/**
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
object Serializers {
|
||||
val ARRAY_OF_BYTE_ARRAY = Array[Class[_]](classOf[Array[Byte]])
|
||||
|
||||
object NOOP extends NOOP
|
||||
class NOOP extends Serializer {
|
||||
def toBinary(obj: AnyRef): Array[Byte] = Array[Byte]()
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = null.asInstanceOf[AnyRef]
|
||||
}
|
||||
|
||||
/**
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
object Java extends Java
|
||||
trait Java extends Serializer {
|
||||
def toBinary(obj: AnyRef): Array[Byte] = {
|
||||
class JavaSerializer extends Serializer {
|
||||
def toBinary(o: AnyRef): Array[Byte] = {
|
||||
val bos = new ByteArrayOutputStream
|
||||
val out = new ObjectOutputStream(bos)
|
||||
out.writeObject(obj)
|
||||
out.close
|
||||
out.writeObject(o)
|
||||
out.close()
|
||||
bos.toByteArray
|
||||
}
|
||||
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]] = None,
|
||||
classLoader: Option[ClassLoader] = None): AnyRef = {
|
||||
val in =
|
||||
if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes))
|
||||
else new ObjectInputStream(new ByteArrayInputStream(bytes))
|
||||
if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes)) else
|
||||
new ObjectInputStream(new ByteArrayInputStream(bytes))
|
||||
val obj = in.readObject
|
||||
in.close
|
||||
in.close()
|
||||
obj
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
object Protobuf extends Protobuf
|
||||
trait Protobuf extends Serializer {
|
||||
def toBinary(obj: AnyRef): Array[Byte] = {
|
||||
if (!obj.isInstanceOf[Message]) throw new IllegalArgumentException(
|
||||
"Can't serialize a non-protobuf message using protobuf [" + obj + "]")
|
||||
obj.asInstanceOf[Message].toByteArray
|
||||
}
|
||||
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
|
||||
if (!clazz.isDefined) throw new IllegalArgumentException(
|
||||
"Need a protobuf message class to be able to serialize bytes using protobuf")
|
||||
clazz.get.getDeclaredMethod("parseFrom", ARRAY_OF_BYTE_ARRAY: _*).invoke(null, bytes).asInstanceOf[Message]
|
||||
}
|
||||
|
||||
def fromBinary(bytes: Array[Byte], clazz: Class[_]): AnyRef = {
|
||||
if (clazz eq null) throw new IllegalArgumentException("Protobuf message can't be null")
|
||||
fromBinary(bytes, Some(clazz))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
object JavaJSON extends JavaJSON
|
||||
trait JavaJSON extends Serializer {
|
||||
private val mapper = new ObjectMapper
|
||||
|
||||
def toBinary(obj: AnyRef): Array[Byte] = {
|
||||
val bos = new ByteArrayOutputStream
|
||||
val out = new ObjectOutputStream(bos)
|
||||
mapper.writeValue(out, obj)
|
||||
out.close
|
||||
bos.toByteArray
|
||||
}
|
||||
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
|
||||
if (!clazz.isDefined) throw new IllegalArgumentException(
|
||||
"Can't deserialize JSON to instance if no class is provided")
|
||||
val in =
|
||||
if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes))
|
||||
else new ObjectInputStream(new ByteArrayInputStream(bytes))
|
||||
val obj = mapper.readValue(in, clazz.get).asInstanceOf[AnyRef]
|
||||
in.close
|
||||
obj
|
||||
}
|
||||
|
||||
def fromJSON(json: String, clazz: Class[_]): AnyRef = {
|
||||
if (clazz eq null) throw new IllegalArgumentException("Can't deserialize JSON to instance if no class is provided")
|
||||
mapper.readValue(json, clazz).asInstanceOf[AnyRef]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
trait ScalaJSON {
|
||||
import sjson.json._
|
||||
|
||||
var classLoader: Option[ClassLoader] = None
|
||||
|
||||
def tojson[T](o: T)(implicit tjs: Writes[T]): JsValue = JsonSerialization.tojson(o)(tjs)
|
||||
|
||||
def fromjson[T](json: JsValue)(implicit fjs: Reads[T]): T = JsonSerialization.fromjson(json)(fjs)
|
||||
|
||||
def tobinary[T](o: T)(implicit tjs: Writes[T]): Array[Byte] = JsonSerialization.tobinary(o)(tjs)
|
||||
|
||||
def frombinary[T](bytes: Array[Byte])(implicit fjs: Reads[T]): T = JsonSerialization.frombinary(bytes)(fjs)
|
||||
|
||||
// backward compatibility
|
||||
// implemented using refelction based json serialization
|
||||
def toBinary(obj: AnyRef): Array[Byte] = SJSONSerializer.SJSON.out(obj)
|
||||
|
||||
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = SJSONSerializer.SJSON.in(bytes)
|
||||
|
||||
import scala.reflect.Manifest
|
||||
def fromJSON[T](json: String)(implicit m: Manifest[T]): AnyRef = {
|
||||
SJSONSerializer.SJSON.in(json)(m)
|
||||
}
|
||||
|
||||
def fromBinary[T](bytes: Array[Byte])(implicit m: Manifest[T]): AnyRef = {
|
||||
SJSONSerializer.SJSON.in(bytes)(m)
|
||||
}
|
||||
}
|
||||
object ScalaJSON extends ScalaJSON
|
||||
}
|
||||
|
||||
object JavaSerializer extends JavaSerializer
|
||||
object Serializer {
|
||||
val defaultSerializerName = JavaSerializer.getClass.getName
|
||||
}
|
||||
|
|
|
|||
422
akka-remote/src/test/java/akka/actor/ProtobufProtocol.java
Normal file
422
akka-remote/src/test/java/akka/actor/ProtobufProtocol.java
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: ProtobufProtocol.proto
|
||||
|
||||
package akka.actor;
|
||||
|
||||
public final class ProtobufProtocol {
|
||||
private ProtobufProtocol() {}
|
||||
public static void registerAllExtensions(
|
||||
com.google.protobuf.ExtensionRegistry registry) {
|
||||
}
|
||||
public static final class MyMessage extends
|
||||
com.google.protobuf.GeneratedMessage {
|
||||
// Use MyMessage.newBuilder() to construct.
|
||||
private MyMessage() {
|
||||
initFields();
|
||||
}
|
||||
private MyMessage(boolean noInit) {}
|
||||
|
||||
private static final MyMessage defaultInstance;
|
||||
public static MyMessage getDefaultInstance() {
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
public MyMessage getDefaultInstanceForType() {
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
public static final com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptor() {
|
||||
return akka.actor.ProtobufProtocol.internal_static_akka_actor_MyMessage_descriptor;
|
||||
}
|
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internalGetFieldAccessorTable() {
|
||||
return akka.actor.ProtobufProtocol.internal_static_akka_actor_MyMessage_fieldAccessorTable;
|
||||
}
|
||||
|
||||
// required uint64 id = 1;
|
||||
public static final int ID_FIELD_NUMBER = 1;
|
||||
private boolean hasId;
|
||||
private long id_ = 0L;
|
||||
public boolean hasId() { return hasId; }
|
||||
public long getId() { return id_; }
|
||||
|
||||
// required string name = 2;
|
||||
public static final int NAME_FIELD_NUMBER = 2;
|
||||
private boolean hasName;
|
||||
private java.lang.String name_ = "";
|
||||
public boolean hasName() { return hasName; }
|
||||
public java.lang.String getName() { return name_; }
|
||||
|
||||
// required bool status = 3;
|
||||
public static final int STATUS_FIELD_NUMBER = 3;
|
||||
private boolean hasStatus;
|
||||
private boolean status_ = false;
|
||||
public boolean hasStatus() { return hasStatus; }
|
||||
public boolean getStatus() { return status_; }
|
||||
|
||||
private void initFields() {
|
||||
}
|
||||
public final boolean isInitialized() {
|
||||
if (!hasId) return false;
|
||||
if (!hasName) return false;
|
||||
if (!hasStatus) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void writeTo(com.google.protobuf.CodedOutputStream output)
|
||||
throws java.io.IOException {
|
||||
getSerializedSize();
|
||||
if (hasId()) {
|
||||
output.writeUInt64(1, getId());
|
||||
}
|
||||
if (hasName()) {
|
||||
output.writeString(2, getName());
|
||||
}
|
||||
if (hasStatus()) {
|
||||
output.writeBool(3, getStatus());
|
||||
}
|
||||
getUnknownFields().writeTo(output);
|
||||
}
|
||||
|
||||
private int memoizedSerializedSize = -1;
|
||||
public int getSerializedSize() {
|
||||
int size = memoizedSerializedSize;
|
||||
if (size != -1) return size;
|
||||
|
||||
size = 0;
|
||||
if (hasId()) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeUInt64Size(1, getId());
|
||||
}
|
||||
if (hasName()) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeStringSize(2, getName());
|
||||
}
|
||||
if (hasStatus()) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeBoolSize(3, getStatus());
|
||||
}
|
||||
size += getUnknownFields().getSerializedSize();
|
||||
memoizedSerializedSize = size;
|
||||
return size;
|
||||
}
|
||||
|
||||
public static akka.actor.ProtobufProtocol.MyMessage parseFrom(
|
||||
com.google.protobuf.ByteString data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static akka.actor.ProtobufProtocol.MyMessage parseFrom(
|
||||
com.google.protobuf.ByteString data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static akka.actor.ProtobufProtocol.MyMessage parseFrom(byte[] data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static akka.actor.ProtobufProtocol.MyMessage parseFrom(
|
||||
byte[] data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static akka.actor.ProtobufProtocol.MyMessage parseFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static akka.actor.ProtobufProtocol.MyMessage parseFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static akka.actor.ProtobufProtocol.MyMessage parseDelimitedFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
Builder builder = newBuilder();
|
||||
if (builder.mergeDelimitedFrom(input)) {
|
||||
return builder.buildParsed();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static akka.actor.ProtobufProtocol.MyMessage parseDelimitedFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
Builder builder = newBuilder();
|
||||
if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
|
||||
return builder.buildParsed();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static akka.actor.ProtobufProtocol.MyMessage parseFrom(
|
||||
com.google.protobuf.CodedInputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static akka.actor.ProtobufProtocol.MyMessage parseFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
|
||||
public static Builder newBuilder() { return Builder.create(); }
|
||||
public Builder newBuilderForType() { return newBuilder(); }
|
||||
public static Builder newBuilder(akka.actor.ProtobufProtocol.MyMessage prototype) {
|
||||
return newBuilder().mergeFrom(prototype);
|
||||
}
|
||||
public Builder toBuilder() { return newBuilder(this); }
|
||||
|
||||
public static final class Builder extends
|
||||
com.google.protobuf.GeneratedMessage.Builder<Builder> {
|
||||
private akka.actor.ProtobufProtocol.MyMessage result;
|
||||
|
||||
// Construct using akka.actor.ProtobufProtocol.MyMessage.newBuilder()
|
||||
private Builder() {}
|
||||
|
||||
private static Builder create() {
|
||||
Builder builder = new Builder();
|
||||
builder.result = new akka.actor.ProtobufProtocol.MyMessage();
|
||||
return builder;
|
||||
}
|
||||
|
||||
protected akka.actor.ProtobufProtocol.MyMessage internalGetResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Builder clear() {
|
||||
if (result == null) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot call clear() after build().");
|
||||
}
|
||||
result = new akka.actor.ProtobufProtocol.MyMessage();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clone() {
|
||||
return create().mergeFrom(result);
|
||||
}
|
||||
|
||||
public com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptorForType() {
|
||||
return akka.actor.ProtobufProtocol.MyMessage.getDescriptor();
|
||||
}
|
||||
|
||||
public akka.actor.ProtobufProtocol.MyMessage getDefaultInstanceForType() {
|
||||
return akka.actor.ProtobufProtocol.MyMessage.getDefaultInstance();
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return result.isInitialized();
|
||||
}
|
||||
public akka.actor.ProtobufProtocol.MyMessage build() {
|
||||
if (result != null && !isInitialized()) {
|
||||
throw newUninitializedMessageException(result);
|
||||
}
|
||||
return buildPartial();
|
||||
}
|
||||
|
||||
private akka.actor.ProtobufProtocol.MyMessage buildParsed()
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
if (!isInitialized()) {
|
||||
throw newUninitializedMessageException(
|
||||
result).asInvalidProtocolBufferException();
|
||||
}
|
||||
return buildPartial();
|
||||
}
|
||||
|
||||
public akka.actor.ProtobufProtocol.MyMessage buildPartial() {
|
||||
if (result == null) {
|
||||
throw new IllegalStateException(
|
||||
"build() has already been called on this Builder.");
|
||||
}
|
||||
akka.actor.ProtobufProtocol.MyMessage returnMe = result;
|
||||
result = null;
|
||||
return returnMe;
|
||||
}
|
||||
|
||||
public Builder mergeFrom(com.google.protobuf.Message other) {
|
||||
if (other instanceof akka.actor.ProtobufProtocol.MyMessage) {
|
||||
return mergeFrom((akka.actor.ProtobufProtocol.MyMessage)other);
|
||||
} else {
|
||||
super.mergeFrom(other);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public Builder mergeFrom(akka.actor.ProtobufProtocol.MyMessage other) {
|
||||
if (other == akka.actor.ProtobufProtocol.MyMessage.getDefaultInstance()) return this;
|
||||
if (other.hasId()) {
|
||||
setId(other.getId());
|
||||
}
|
||||
if (other.hasName()) {
|
||||
setName(other.getName());
|
||||
}
|
||||
if (other.hasStatus()) {
|
||||
setStatus(other.getStatus());
|
||||
}
|
||||
this.mergeUnknownFields(other.getUnknownFields());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder mergeFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
|
||||
com.google.protobuf.UnknownFieldSet.newBuilder(
|
||||
this.getUnknownFields());
|
||||
while (true) {
|
||||
int tag = input.readTag();
|
||||
switch (tag) {
|
||||
case 0:
|
||||
this.setUnknownFields(unknownFields.build());
|
||||
return this;
|
||||
default: {
|
||||
if (!parseUnknownField(input, unknownFields,
|
||||
extensionRegistry, tag)) {
|
||||
this.setUnknownFields(unknownFields.build());
|
||||
return this;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
setId(input.readUInt64());
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
setName(input.readString());
|
||||
break;
|
||||
}
|
||||
case 24: {
|
||||
setStatus(input.readBool());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// required uint64 id = 1;
|
||||
public boolean hasId() {
|
||||
return result.hasId();
|
||||
}
|
||||
public long getId() {
|
||||
return result.getId();
|
||||
}
|
||||
public Builder setId(long value) {
|
||||
result.hasId = true;
|
||||
result.id_ = value;
|
||||
return this;
|
||||
}
|
||||
public Builder clearId() {
|
||||
result.hasId = false;
|
||||
result.id_ = 0L;
|
||||
return this;
|
||||
}
|
||||
|
||||
// required string name = 2;
|
||||
public boolean hasName() {
|
||||
return result.hasName();
|
||||
}
|
||||
public java.lang.String getName() {
|
||||
return result.getName();
|
||||
}
|
||||
public Builder setName(java.lang.String value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
result.hasName = true;
|
||||
result.name_ = value;
|
||||
return this;
|
||||
}
|
||||
public Builder clearName() {
|
||||
result.hasName = false;
|
||||
result.name_ = getDefaultInstance().getName();
|
||||
return this;
|
||||
}
|
||||
|
||||
// required bool status = 3;
|
||||
public boolean hasStatus() {
|
||||
return result.hasStatus();
|
||||
}
|
||||
public boolean getStatus() {
|
||||
return result.getStatus();
|
||||
}
|
||||
public Builder setStatus(boolean value) {
|
||||
result.hasStatus = true;
|
||||
result.status_ = value;
|
||||
return this;
|
||||
}
|
||||
public Builder clearStatus() {
|
||||
result.hasStatus = false;
|
||||
result.status_ = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(builder_scope:akka.actor.MyMessage)
|
||||
}
|
||||
|
||||
static {
|
||||
defaultInstance = new MyMessage(true);
|
||||
akka.actor.ProtobufProtocol.internalForceInit();
|
||||
defaultInstance.initFields();
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(class_scope:akka.actor.MyMessage)
|
||||
}
|
||||
|
||||
private static com.google.protobuf.Descriptors.Descriptor
|
||||
internal_static_akka_actor_MyMessage_descriptor;
|
||||
private static
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internal_static_akka_actor_MyMessage_fieldAccessorTable;
|
||||
|
||||
public static com.google.protobuf.Descriptors.FileDescriptor
|
||||
getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
private static com.google.protobuf.Descriptors.FileDescriptor
|
||||
descriptor;
|
||||
static {
|
||||
java.lang.String[] descriptorData = {
|
||||
"\n\026ProtobufProtocol.proto\022\nakka.actor\"5\n\t" +
|
||||
"MyMessage\022\n\n\002id\030\001 \002(\004\022\014\n\004name\030\002 \002(\t\022\016\n\006s" +
|
||||
"tatus\030\003 \002(\010"
|
||||
};
|
||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
||||
public com.google.protobuf.ExtensionRegistry assignDescriptors(
|
||||
com.google.protobuf.Descriptors.FileDescriptor root) {
|
||||
descriptor = root;
|
||||
internal_static_akka_actor_MyMessage_descriptor =
|
||||
getDescriptor().getMessageTypes().get(0);
|
||||
internal_static_akka_actor_MyMessage_fieldAccessorTable = new
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_akka_actor_MyMessage_descriptor,
|
||||
new java.lang.String[] { "Id", "Name", "Status", },
|
||||
akka.actor.ProtobufProtocol.MyMessage.class,
|
||||
akka.actor.ProtobufProtocol.MyMessage.Builder.class);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
com.google.protobuf.Descriptors.FileDescriptor
|
||||
.internalBuildGeneratedFileFrom(descriptorData,
|
||||
new com.google.protobuf.Descriptors.FileDescriptor[] {
|
||||
}, assigner);
|
||||
}
|
||||
|
||||
public static void internalForceInit() {}
|
||||
|
||||
// @@protoc_insertion_point(outer_class_scope)
|
||||
}
|
||||
18
akka-remote/src/test/protocol/ProtobufProtocol.proto
Normal file
18
akka-remote/src/test/protocol/ProtobufProtocol.proto
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2011 Scalable Solutions AB <http://scalablesolutions.se>
|
||||
*/
|
||||
|
||||
package akka.actor;
|
||||
|
||||
/*
|
||||
Compile with:
|
||||
cd ./akka-remote/src/test/protocol
|
||||
protoc ProtobufProtocol.proto --java_out ../java
|
||||
*/
|
||||
|
||||
message MyMessage {
|
||||
required uint64 id = 1;
|
||||
required string name = 2;
|
||||
required bool status = 3;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
package akka.serialization
|
||||
|
||||
import org.scalatest.Spec
|
||||
import org.scalatest.matchers.ShouldMatchers
|
||||
import org.scalatest.BeforeAndAfterAll
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import com.google.protobuf.Message
|
||||
|
||||
import akka.serialization.ActorSerialization._
|
||||
import akka.actor._
|
||||
import Actor._
|
||||
import SerializeSpec._
|
||||
|
||||
case class MyMessage(id: Long, name: String, status: Boolean)
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class ActorSerializeSpec extends Spec with ShouldMatchers with BeforeAndAfterAll {
|
||||
|
||||
describe("Serializable actor") {
|
||||
it("should be able to serialize and de-serialize a stateful actor with a given serializer") {
|
||||
|
||||
val actor1 = actorOf[MyJavaSerializableActor].start()
|
||||
(actor1 !! "hello").getOrElse("_") should equal("world 1")
|
||||
(actor1 !! "hello").getOrElse("_") should equal("world 2")
|
||||
|
||||
val bytes = toBinary(actor1)
|
||||
val actor2 = fromBinary(bytes)
|
||||
actor2.start()
|
||||
(actor2 !! "hello").getOrElse("_") should equal("world 3")
|
||||
|
||||
actor2.receiveTimeout should equal(Some(1000))
|
||||
actor1.stop()
|
||||
actor2.stop()
|
||||
}
|
||||
|
||||
it("should be able to serialize and deserialize a MyStatelessActorWithMessagesInMailbox") {
|
||||
|
||||
val actor1 = actorOf[MyStatelessActorWithMessagesInMailbox].start()
|
||||
(actor1 ! "hello")
|
||||
(actor1 ! "hello")
|
||||
(actor1 ! "hello")
|
||||
(actor1 ! "hello")
|
||||
(actor1 ! "hello")
|
||||
(actor1 ! "hello")
|
||||
(actor1 ! "hello")
|
||||
(actor1 ! "hello")
|
||||
(actor1 ! "hello")
|
||||
(actor1 ! "hello")
|
||||
actor1.mailboxSize should be > (0)
|
||||
val actor2 = fromBinary(toBinary(actor1))
|
||||
Thread.sleep(1000)
|
||||
actor2.mailboxSize should be > (0)
|
||||
(actor2 !! "hello-reply").getOrElse("_") should equal("world")
|
||||
|
||||
val actor3 = fromBinary(toBinary(actor1, false))
|
||||
Thread.sleep(1000)
|
||||
actor3.mailboxSize should equal(0)
|
||||
(actor3 !! "hello-reply").getOrElse("_") should equal("world")
|
||||
}
|
||||
|
||||
it("should be able to serialize and deserialize a PersonActorWithMessagesInMailbox") {
|
||||
|
||||
val p1 = Person("debasish ghosh", 25, SerializeSpec.Address("120", "Monroe Street", "Santa Clara", "95050"))
|
||||
val actor1 = actorOf[PersonActorWithMessagesInMailbox].start()
|
||||
(actor1 ! p1)
|
||||
(actor1 ! p1)
|
||||
(actor1 ! p1)
|
||||
(actor1 ! p1)
|
||||
(actor1 ! p1)
|
||||
(actor1 ! p1)
|
||||
(actor1 ! p1)
|
||||
(actor1 ! p1)
|
||||
(actor1 ! p1)
|
||||
(actor1 ! p1)
|
||||
actor1.mailboxSize should be > (0)
|
||||
val actor2 = fromBinary(toBinary(actor1))
|
||||
Thread.sleep(1000)
|
||||
actor2.mailboxSize should be > (0)
|
||||
(actor2 !! "hello-reply").getOrElse("_") should equal("hello")
|
||||
|
||||
val actor3 = fromBinary(toBinary(actor1, false))
|
||||
Thread.sleep(1000)
|
||||
actor3.mailboxSize should equal(0)
|
||||
(actor3 !! "hello-reply").getOrElse("_") should equal("hello")
|
||||
}
|
||||
}
|
||||
|
||||
describe("serialize protobuf") {
|
||||
it("should serialize") {
|
||||
val msg = MyMessage(123, "debasish ghosh", true)
|
||||
import akka.serialization.Serialization._
|
||||
val b = serialize(ProtobufProtocol.MyMessage.newBuilder.setId(msg.id).setName(msg.name).setStatus(msg.status).build) match {
|
||||
case Left(exception) ⇒ fail(exception)
|
||||
case Right(bytes) ⇒ bytes
|
||||
}
|
||||
val in = deserialize(b, classOf[ProtobufProtocol.MyMessage], None) match {
|
||||
case Left(exception) ⇒ fail(exception)
|
||||
case Right(i) ⇒ i
|
||||
}
|
||||
val m = in.asInstanceOf[ProtobufProtocol.MyMessage]
|
||||
MyMessage(m.getId, m.getName, m.getStatus) should equal(msg)
|
||||
}
|
||||
}
|
||||
|
||||
describe("serialize actor that accepts protobuf message") {
|
||||
it("should serialize") {
|
||||
|
||||
val actor1 = actorOf[MyActorWithProtobufMessagesInMailbox].start()
|
||||
val msg = MyMessage(123, "debasish ghosh", true)
|
||||
val b = ProtobufProtocol.MyMessage.newBuilder.setId(msg.id).setName(msg.name).setStatus(msg.status).build
|
||||
(actor1 ! b)
|
||||
(actor1 ! b)
|
||||
(actor1 ! b)
|
||||
(actor1 ! b)
|
||||
(actor1 ! b)
|
||||
(actor1 ! b)
|
||||
(actor1 ! b)
|
||||
(actor1 ! b)
|
||||
(actor1 ! b)
|
||||
(actor1 ! b)
|
||||
actor1.mailboxSize should be > (0)
|
||||
val actor2 = fromBinary(toBinary(actor1))
|
||||
Thread.sleep(1000)
|
||||
actor2.mailboxSize should be > (0)
|
||||
(actor2 !! "hello-reply").getOrElse("_") should equal("world")
|
||||
|
||||
val actor3 = fromBinary(toBinary(actor1, false))
|
||||
Thread.sleep(1000)
|
||||
actor3.mailboxSize should equal(0)
|
||||
(actor3 !! "hello-reply").getOrElse("_") should equal("world")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyJavaSerializableActor extends Actor with scala.Serializable {
|
||||
var count = 0
|
||||
self.receiveTimeout = Some(1000)
|
||||
|
||||
def receive = {
|
||||
case "hello" ⇒
|
||||
count = count + 1
|
||||
self.reply("world " + count)
|
||||
}
|
||||
}
|
||||
|
||||
class MyStatelessActorWithMessagesInMailbox extends Actor with scala.Serializable {
|
||||
def receive = {
|
||||
case "hello" ⇒
|
||||
Thread.sleep(500)
|
||||
case "hello-reply" ⇒ self.reply("world")
|
||||
}
|
||||
}
|
||||
|
||||
class MyActorWithProtobufMessagesInMailbox extends Actor with scala.Serializable {
|
||||
def receive = {
|
||||
case m: Message ⇒
|
||||
Thread.sleep(500)
|
||||
case "hello-reply" ⇒ self.reply("world")
|
||||
}
|
||||
}
|
||||
|
||||
class PersonActorWithMessagesInMailbox extends Actor with scala.Serializable {
|
||||
def receive = {
|
||||
case p: Person ⇒
|
||||
Thread.sleep(500)
|
||||
case "hello-reply" ⇒ self.reply("hello")
|
||||
}
|
||||
}
|
||||
|
|
@ -682,6 +682,9 @@ class AkkaParentProject(info: ProjectInfo) extends ParentProject(info) with Exec
|
|||
val junit = Dependencies.junit
|
||||
val scalatest = Dependencies.scalatest
|
||||
val multiverse_test = Dependencies.multiverse_test // StandardLatch
|
||||
val protobuf = Dependencies.protobuf
|
||||
val jackson = Dependencies.jackson
|
||||
val sjson = Dependencies.sjson
|
||||
override def compileOptions = super.compileOptions ++ compileOptions("-P:continuations:enable")
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue