2013-10-09 13:11:53 +02:00
|
|
|
/**
|
2014-02-02 19:05:45 -06:00
|
|
|
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
2013-10-09 13:11:53 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package akka.persistence.serialization
|
|
|
|
|
|
|
|
|
|
import scala.language.existentials
|
|
|
|
|
import com.google.protobuf._
|
2014-01-17 06:58:25 +01:00
|
|
|
import akka.actor.{ ActorPath, ExtendedActorSystem }
|
2013-10-27 08:01:14 +01:00
|
|
|
import akka.japi.Util.immutableSeq
|
2013-10-09 13:11:53 +02:00
|
|
|
import akka.persistence._
|
|
|
|
|
import akka.persistence.serialization.MessageFormats._
|
|
|
|
|
import akka.serialization._
|
2014-06-03 15:10:56 +02:00
|
|
|
import akka.persistence.AtLeastOnceDelivery.{ AtLeastOnceDeliverySnapshot ⇒ AtLeastOnceDeliverySnap }
|
|
|
|
|
import akka.persistence.AtLeastOnceDelivery.UnconfirmedDelivery
|
|
|
|
|
import scala.collection.immutable.VectorBuilder
|
2013-10-09 13:11:53 +02:00
|
|
|
|
|
|
|
|
/**
|
2013-11-07 10:45:02 +01:00
|
|
|
* Marker trait for all protobuf-serializable messages in `akka.persistence`.
|
|
|
|
|
*/
|
|
|
|
|
trait Message extends Serializable
|
|
|
|
|
|
|
|
|
|
/**
|
2014-12-08 11:02:14 +01:00
|
|
|
* Protobuf serializer for [[PersistentRepr]] and [[AtLeastOnceDelivery]] messages.
|
2013-10-09 13:11:53 +02:00
|
|
|
*/
|
2015-03-05 11:55:05 -06:00
|
|
|
class MessageSerializer(val system: ExtendedActorSystem) extends BaseSerializer {
|
2013-11-07 10:45:02 +01:00
|
|
|
import PersistentRepr.Undefined
|
2013-10-09 13:11:53 +02:00
|
|
|
|
2013-11-07 10:45:02 +01:00
|
|
|
val PersistentReprClass = classOf[PersistentRepr]
|
|
|
|
|
val PersistentImplClass = classOf[PersistentImpl]
|
2014-06-03 15:10:56 +02:00
|
|
|
val AtLeastOnceDeliverySnapshotClass = classOf[AtLeastOnceDeliverySnap]
|
2013-10-09 13:11:53 +02:00
|
|
|
|
2015-02-08 19:12:02 -06:00
|
|
|
override val includeManifest: Boolean = true
|
2013-10-09 13:11:53 +02:00
|
|
|
|
2014-04-06 21:33:31 +02:00
|
|
|
private lazy val transportInformation: Option[Serialization.Information] = {
|
|
|
|
|
val address = system.provider.getDefaultAddress
|
|
|
|
|
if (address.hasLocalScope) None
|
|
|
|
|
else Some(Serialization.Information(address, system))
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-09 13:11:53 +02:00
|
|
|
/**
|
2014-12-08 11:02:14 +01:00
|
|
|
* Serializes persistent messages. Delegates serialization of a persistent
|
|
|
|
|
* message's payload to a matching `akka.serialization.Serializer`.
|
2013-10-09 13:11:53 +02:00
|
|
|
*/
|
|
|
|
|
def toBinary(o: AnyRef): Array[Byte] = o match {
|
2014-12-08 11:02:14 +01:00
|
|
|
case p: PersistentRepr ⇒ persistentMessageBuilder(p).build().toByteArray
|
|
|
|
|
case a: AtLeastOnceDeliverySnap ⇒ atLeastOnceDeliverySnapshotBuilder(a).build.toByteArray
|
|
|
|
|
case _ ⇒ throw new IllegalArgumentException(s"Can't serialize object of type ${o.getClass}")
|
2013-10-09 13:11:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2014-12-08 11:02:14 +01:00
|
|
|
* Deserializes persistent messages. Delegates deserialization of a persistent
|
|
|
|
|
* message's payload to a matching `akka.serialization.Serializer`.
|
2013-10-09 13:11:53 +02:00
|
|
|
*/
|
2013-11-07 10:45:02 +01:00
|
|
|
def fromBinary(bytes: Array[Byte], manifest: Option[Class[_]]): Message = manifest match {
|
2013-10-09 13:11:53 +02:00
|
|
|
case None ⇒ persistent(PersistentMessage.parseFrom(bytes))
|
|
|
|
|
case Some(c) ⇒ c match {
|
2014-12-08 11:02:14 +01:00
|
|
|
case PersistentImplClass ⇒ persistent(PersistentMessage.parseFrom(bytes))
|
|
|
|
|
case PersistentReprClass ⇒ persistent(PersistentMessage.parseFrom(bytes))
|
|
|
|
|
case AtLeastOnceDeliverySnapshotClass ⇒ atLeastOnceDeliverySnapshot(AtLeastOnceDeliverySnapshot.parseFrom(bytes))
|
|
|
|
|
case _ ⇒ throw new IllegalArgumentException(s"Can't deserialize object of type ${c}")
|
2013-10-09 13:11:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// toBinary helpers
|
|
|
|
|
//
|
|
|
|
|
|
2014-06-03 15:10:56 +02:00
|
|
|
def atLeastOnceDeliverySnapshotBuilder(snap: AtLeastOnceDeliverySnap): AtLeastOnceDeliverySnapshot.Builder = {
|
|
|
|
|
val builder = AtLeastOnceDeliverySnapshot.newBuilder
|
|
|
|
|
builder.setCurrentDeliveryId(snap.currentDeliveryId)
|
|
|
|
|
snap.unconfirmedDeliveries.foreach { unconfirmed ⇒
|
|
|
|
|
val unconfirmedBuilder =
|
|
|
|
|
AtLeastOnceDeliverySnapshot.UnconfirmedDelivery.newBuilder.
|
|
|
|
|
setDeliveryId(unconfirmed.deliveryId).
|
|
|
|
|
setDestination(unconfirmed.destination.toString).
|
|
|
|
|
setPayload(persistentPayloadBuilder(unconfirmed.message.asInstanceOf[AnyRef]))
|
|
|
|
|
builder.addUnconfirmedDeliveries(unconfirmedBuilder)
|
|
|
|
|
}
|
|
|
|
|
builder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def atLeastOnceDeliverySnapshot(atLeastOnceDeliverySnapshot: AtLeastOnceDeliverySnapshot): AtLeastOnceDeliverySnap = {
|
|
|
|
|
import scala.collection.JavaConverters._
|
|
|
|
|
val unconfirmedDeliveries = new VectorBuilder[UnconfirmedDelivery]()
|
|
|
|
|
atLeastOnceDeliverySnapshot.getUnconfirmedDeliveriesList().iterator().asScala foreach { next ⇒
|
|
|
|
|
unconfirmedDeliveries += UnconfirmedDelivery(next.getDeliveryId, ActorPath.fromString(next.getDestination),
|
|
|
|
|
payload(next.getPayload))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AtLeastOnceDeliverySnap(
|
|
|
|
|
atLeastOnceDeliverySnapshot.getCurrentDeliveryId,
|
|
|
|
|
unconfirmedDeliveries.result())
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-07 10:45:02 +01:00
|
|
|
private def persistentMessageBuilder(persistent: PersistentRepr) = {
|
2013-10-09 13:11:53 +02:00
|
|
|
val builder = PersistentMessage.newBuilder
|
|
|
|
|
|
2014-06-23 14:33:35 +02:00
|
|
|
if (persistent.persistenceId != Undefined) builder.setPersistenceId(persistent.persistenceId)
|
2013-10-09 13:11:53 +02:00
|
|
|
if (persistent.sender != null) builder.setSender(Serialization.serializedActorPath(persistent.sender))
|
|
|
|
|
|
|
|
|
|
builder.setPayload(persistentPayloadBuilder(persistent.payload.asInstanceOf[AnyRef]))
|
|
|
|
|
builder.setSequenceNr(persistent.sequenceNr)
|
|
|
|
|
builder.setDeleted(persistent.deleted)
|
|
|
|
|
builder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private def persistentPayloadBuilder(payload: AnyRef) = {
|
2014-04-06 21:33:31 +02:00
|
|
|
def payloadBuilder() = {
|
|
|
|
|
val serializer = SerializationExtension(system).findSerializerFor(payload)
|
|
|
|
|
val builder = PersistentPayload.newBuilder()
|
2013-10-09 13:11:53 +02:00
|
|
|
|
2014-06-23 14:33:35 +02:00
|
|
|
if (serializer.includeManifest) builder.setPayloadManifest(ByteString.copyFromUtf8(payload.getClass.getName))
|
2013-10-09 13:11:53 +02:00
|
|
|
|
2014-04-06 21:33:31 +02:00
|
|
|
builder.setPayload(ByteString.copyFrom(serializer.toBinary(payload)))
|
|
|
|
|
builder.setSerializerId(serializer.identifier)
|
|
|
|
|
builder
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
// serialize actor references with full address information (defaultAddress)
|
2014-04-06 21:33:31 +02:00
|
|
|
transportInformation match {
|
|
|
|
|
case Some(ti) ⇒ Serialization.currentTransportInformation.withValue(ti) { payloadBuilder() }
|
|
|
|
|
case None ⇒ payloadBuilder()
|
|
|
|
|
}
|
2013-10-09 13:11:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// fromBinary helpers
|
|
|
|
|
//
|
|
|
|
|
|
2013-11-07 10:45:02 +01:00
|
|
|
private def persistent(persistentMessage: PersistentMessage): PersistentRepr = {
|
|
|
|
|
PersistentRepr(
|
2013-10-09 13:11:53 +02:00
|
|
|
payload(persistentMessage.getPayload),
|
|
|
|
|
persistentMessage.getSequenceNr,
|
2014-06-23 14:33:35 +02:00
|
|
|
if (persistentMessage.hasPersistenceId) persistentMessage.getPersistenceId else Undefined,
|
2013-10-09 13:11:53 +02:00
|
|
|
persistentMessage.getDeleted,
|
|
|
|
|
if (persistentMessage.hasSender) system.provider.resolveActorRef(persistentMessage.getSender) else null)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private def payload(persistentPayload: PersistentPayload): Any = {
|
|
|
|
|
val payloadClass = if (persistentPayload.hasPayloadManifest)
|
|
|
|
|
Some(system.dynamicAccess.getClassFor[AnyRef](persistentPayload.getPayloadManifest.toStringUtf8).get) else None
|
|
|
|
|
|
|
|
|
|
SerializationExtension(system).deserialize(
|
|
|
|
|
persistentPayload.getPayload.toByteArray,
|
|
|
|
|
persistentPayload.getSerializerId,
|
|
|
|
|
payloadClass).get
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|