2013-10-09 13:11:53 +02:00
|
|
|
/**
|
2015-03-07 22:58:48 -08:00
|
|
|
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
2013-10-09 13:11:53 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package akka.persistence.serialization
|
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
import akka.actor.{ ActorPath, ExtendedActorSystem }
|
2015-05-29 18:20:51 +02:00
|
|
|
import akka.persistence.AtLeastOnceDelivery.{ AtLeastOnceDeliverySnapshot ⇒ AtLeastOnceDeliverySnap, UnconfirmedDelivery }
|
2013-10-09 13:11:53 +02:00
|
|
|
import akka.persistence._
|
2015-05-29 18:20:51 +02:00
|
|
|
import akka.persistence.fsm.PersistentFsmActor.StateChangeEvent
|
2013-10-09 13:11:53 +02:00
|
|
|
import akka.persistence.serialization.MessageFormats._
|
|
|
|
|
import akka.serialization._
|
2015-05-29 18:20:51 +02:00
|
|
|
import com.google.protobuf._
|
|
|
|
|
|
2014-06-03 15:10:56 +02:00
|
|
|
import scala.collection.immutable.VectorBuilder
|
2015-05-29 18:20:51 +02:00
|
|
|
import scala.concurrent.duration
|
2015-06-16 15:17:48 +02:00
|
|
|
import akka.actor.Actor
|
2015-05-29 18:20:51 +02:00
|
|
|
import scala.concurrent.duration.Duration
|
|
|
|
|
import scala.language.existentials
|
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-11-09 14:12:36 +02:00
|
|
|
* Protobuf serializer for [[akka.persistence.PersistentRepr]], [[akka.persistence.AtLeastOnceDelivery]] and [[akka.persistence.fsm.PersistentFsmActor.StateChangeEvent]] 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]
|
2014-11-09 14:12:36 +02:00
|
|
|
val PersistentStateChangeEventClass = classOf[StateChangeEvent]
|
2013-10-09 13:11:53 +02:00
|
|
|
|
2015-05-28 18:42:22 +02:00
|
|
|
private lazy val serialization = SerializationExtension(system)
|
|
|
|
|
|
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
|
2014-11-09 14:12:36 +02:00
|
|
|
case s: StateChangeEvent ⇒ stateChangeBuilder(s).build.toByteArray
|
2014-12-08 11:02:14 +01:00
|
|
|
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))
|
2014-11-09 14:12:36 +02:00
|
|
|
case PersistentStateChangeEventClass ⇒ stateChange(PersistentStateChangeEvent.parseFrom(bytes))
|
2014-12-08 11:02:14 +01:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-09 14:12:36 +02:00
|
|
|
def stateChangeBuilder(stateChange: StateChangeEvent): PersistentStateChangeEvent.Builder = {
|
|
|
|
|
val builder = PersistentStateChangeEvent.newBuilder.setStateIdentifier(stateChange.stateIdentifier)
|
|
|
|
|
stateChange.timeout match {
|
|
|
|
|
case None ⇒ builder
|
|
|
|
|
case Some(timeout) ⇒ builder.setTimeout(timeout.toString())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-03 15:10:56 +02:00
|
|
|
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())
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-09 14:12:36 +02:00
|
|
|
def stateChange(persistentStateChange: PersistentStateChangeEvent): StateChangeEvent = {
|
|
|
|
|
StateChangeEvent(
|
|
|
|
|
persistentStateChange.getStateIdentifier,
|
|
|
|
|
if (persistentStateChange.hasTimeout) Some(Duration(persistentStateChange.getTimeout).asInstanceOf[duration.FiniteDuration]) else None)
|
|
|
|
|
}
|
|
|
|
|
|
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)
|
2015-06-16 15:17:48 +02:00
|
|
|
if (persistent.sender != Actor.noSender) builder.setSender(Serialization.serializedActorPath(persistent.sender))
|
2013-10-09 13:11:53 +02:00
|
|
|
|
|
|
|
|
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() = {
|
2015-05-28 18:42:22 +02:00
|
|
|
val serializer = serialization.findSerializerFor(payload)
|
2014-04-06 21:33:31 +02:00
|
|
|
val builder = PersistentPayload.newBuilder()
|
2013-10-09 13:11:53 +02:00
|
|
|
|
2015-05-28 18:42:22 +02:00
|
|
|
serializer match {
|
|
|
|
|
case ser2: SerializerWithStringManifest ⇒
|
|
|
|
|
val manifest = ser2.manifest(payload)
|
|
|
|
|
if (manifest != "")
|
|
|
|
|
builder.setPayloadManifest(ByteString.copyFromUtf8(manifest))
|
|
|
|
|
case _ ⇒
|
|
|
|
|
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,
|
2015-05-29 18:20:51 +02:00
|
|
|
if (persistentMessage.hasManifest) persistentMessage.getManifest else Undefined,
|
2013-10-09 13:11:53 +02:00
|
|
|
persistentMessage.getDeleted,
|
2015-06-16 15:17:48 +02:00
|
|
|
if (persistentMessage.hasSender) system.provider.resolveActorRef(persistentMessage.getSender) else Actor.noSender)
|
2013-10-09 13:11:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private def payload(persistentPayload: PersistentPayload): Any = {
|
2015-05-28 18:42:22 +02:00
|
|
|
val manifest = if (persistentPayload.hasPayloadManifest)
|
|
|
|
|
persistentPayload.getPayloadManifest.toStringUtf8 else ""
|
2013-10-09 13:11:53 +02:00
|
|
|
|
2015-05-28 18:42:22 +02:00
|
|
|
serialization.deserialize(
|
2013-10-09 13:11:53 +02:00
|
|
|
persistentPayload.getPayload.toByteArray,
|
|
|
|
|
persistentPayload.getSerializerId,
|
2015-05-28 18:42:22 +02:00
|
|
|
manifest).get
|
2013-10-09 13:11:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|