2013-10-09 13:11:53 +02:00
|
|
|
/**
|
2018-01-04 17:26:29 +00:00
|
|
|
* Copyright (C) 2009-2018 Lightbend Inc. <https://www.lightbend.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-06-23 21:01:36 +02:00
|
|
|
import akka.persistence.AtLeastOnceDelivery._
|
2013-10-09 13:11:53 +02:00
|
|
|
import akka.persistence._
|
2016-04-14 02:31:33 +03:00
|
|
|
import akka.persistence.fsm.PersistentFSM.{ PersistentFSMSnapshot, StateChangeEvent }
|
2015-06-23 21:01:36 +02:00
|
|
|
import akka.persistence.serialization.{ MessageFormats ⇒ mf }
|
2013-10-09 13:11:53 +02:00
|
|
|
import akka.serialization._
|
2015-02-18 00:15:50 +01:00
|
|
|
import akka.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
|
2016-12-16 11:36:04 +01:00
|
|
|
import java.io.NotSerializableException
|
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
|
|
|
|
|
|
|
|
|
|
/**
|
2015-08-10 16:22:50 +02:00
|
|
|
* Protobuf serializer for [[akka.persistence.PersistentRepr]], [[akka.persistence.AtLeastOnceDelivery]] and [[akka.persistence.fsm.PersistentFSM.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
|
|
|
|
2015-06-23 21:01:36 +02:00
|
|
|
val AtomicWriteClass = classOf[AtomicWrite]
|
2013-11-07 10:45:02 +01:00
|
|
|
val PersistentReprClass = classOf[PersistentRepr]
|
|
|
|
|
val PersistentImplClass = classOf[PersistentImpl]
|
2015-06-23 21:01:36 +02:00
|
|
|
val AtLeastOnceDeliverySnapshotClass = classOf[AtLeastOnceDeliverySnapshot]
|
2014-11-09 14:12:36 +02:00
|
|
|
val PersistentStateChangeEventClass = classOf[StateChangeEvent]
|
2016-04-14 02:31:33 +03:00
|
|
|
val PersistentFSMSnapshotClass = classOf[PersistentFSMSnapshot[Any]]
|
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-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 {
|
2015-06-23 21:01:36 +02:00
|
|
|
case p: PersistentRepr ⇒ persistentMessageBuilder(p).build().toByteArray
|
|
|
|
|
case a: AtomicWrite ⇒ atomicWriteBuilder(a).build().toByteArray
|
|
|
|
|
case a: AtLeastOnceDeliverySnapshot ⇒ atLeastOnceDeliverySnapshotBuilder(a).build.toByteArray
|
|
|
|
|
case s: StateChangeEvent ⇒ stateChangeBuilder(s).build.toByteArray
|
2016-04-14 02:31:33 +03:00
|
|
|
case p: PersistentFSMSnapshot[Any] ⇒ persistentFSMSnapshotBuilder(p).build.toByteArray
|
2015-06-23 21:01:36 +02: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 {
|
2015-06-23 21:01:36 +02:00
|
|
|
case None ⇒ persistent(mf.PersistentMessage.parseFrom(bytes))
|
2013-10-09 13:11:53 +02:00
|
|
|
case Some(c) ⇒ c match {
|
2015-06-23 21:01:36 +02:00
|
|
|
case PersistentImplClass ⇒ persistent(mf.PersistentMessage.parseFrom(bytes))
|
|
|
|
|
case PersistentReprClass ⇒ persistent(mf.PersistentMessage.parseFrom(bytes))
|
|
|
|
|
case AtomicWriteClass ⇒ atomicWrite(mf.AtomicWrite.parseFrom(bytes))
|
|
|
|
|
case AtLeastOnceDeliverySnapshotClass ⇒ atLeastOnceDeliverySnapshot(mf.AtLeastOnceDeliverySnapshot.parseFrom(bytes))
|
|
|
|
|
case PersistentStateChangeEventClass ⇒ stateChange(mf.PersistentStateChangeEvent.parseFrom(bytes))
|
2016-04-14 02:31:33 +03:00
|
|
|
case PersistentFSMSnapshotClass ⇒ persistentFSMSnapshot(mf.PersistentFSMSnapshot.parseFrom(bytes))
|
2016-12-16 11:36:04 +01:00
|
|
|
case _ ⇒ throw new NotSerializableException(s"Can't deserialize object of type ${c}")
|
2013-10-09 13:11:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// toBinary helpers
|
|
|
|
|
//
|
|
|
|
|
|
2015-06-23 21:01:36 +02:00
|
|
|
def atLeastOnceDeliverySnapshotBuilder(snap: AtLeastOnceDeliverySnapshot): mf.AtLeastOnceDeliverySnapshot.Builder = {
|
|
|
|
|
val builder = mf.AtLeastOnceDeliverySnapshot.newBuilder
|
2014-06-03 15:10:56 +02:00
|
|
|
builder.setCurrentDeliveryId(snap.currentDeliveryId)
|
|
|
|
|
snap.unconfirmedDeliveries.foreach { unconfirmed ⇒
|
|
|
|
|
val unconfirmedBuilder =
|
2015-06-23 21:01:36 +02:00
|
|
|
mf.AtLeastOnceDeliverySnapshot.UnconfirmedDelivery.newBuilder.
|
2014-06-03 15:10:56 +02:00
|
|
|
setDeliveryId(unconfirmed.deliveryId).
|
|
|
|
|
setDestination(unconfirmed.destination.toString).
|
|
|
|
|
setPayload(persistentPayloadBuilder(unconfirmed.message.asInstanceOf[AnyRef]))
|
|
|
|
|
builder.addUnconfirmedDeliveries(unconfirmedBuilder)
|
|
|
|
|
}
|
|
|
|
|
builder
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-23 21:01:36 +02:00
|
|
|
private[persistence] def stateChangeBuilder(stateChange: StateChangeEvent): mf.PersistentStateChangeEvent.Builder = {
|
|
|
|
|
val builder = mf.PersistentStateChangeEvent.newBuilder.setStateIdentifier(stateChange.stateIdentifier)
|
2014-11-09 14:12:36 +02:00
|
|
|
stateChange.timeout match {
|
|
|
|
|
case None ⇒ builder
|
2016-04-14 02:31:33 +03:00
|
|
|
case Some(timeout) ⇒ builder.setTimeoutNanos(timeout.toNanos)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private[persistence] def persistentFSMSnapshotBuilder(persistentFSMSnapshot: PersistentFSMSnapshot[Any]): mf.PersistentFSMSnapshot.Builder = {
|
|
|
|
|
val builder = mf.PersistentFSMSnapshot.newBuilder
|
|
|
|
|
.setStateIdentifier(persistentFSMSnapshot.stateIdentifier)
|
|
|
|
|
.setData(persistentPayloadBuilder(persistentFSMSnapshot.data.asInstanceOf[AnyRef]))
|
|
|
|
|
persistentFSMSnapshot.timeout match {
|
|
|
|
|
case None ⇒ builder
|
|
|
|
|
case Some(timeout) ⇒ builder.setTimeoutNanos(timeout.toNanos)
|
2014-11-09 14:12:36 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-23 21:01:36 +02:00
|
|
|
def atLeastOnceDeliverySnapshot(atLeastOnceDeliverySnapshot: mf.AtLeastOnceDeliverySnapshot): AtLeastOnceDeliverySnapshot = {
|
2014-06-03 15:10:56 +02:00
|
|
|
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))
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-23 21:01:36 +02:00
|
|
|
AtLeastOnceDeliverySnapshot(
|
2014-06-03 15:10:56 +02:00
|
|
|
atLeastOnceDeliverySnapshot.getCurrentDeliveryId,
|
|
|
|
|
unconfirmedDeliveries.result())
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-23 21:01:36 +02:00
|
|
|
def stateChange(persistentStateChange: mf.PersistentStateChangeEvent): StateChangeEvent = {
|
2014-11-09 14:12:36 +02:00
|
|
|
StateChangeEvent(
|
|
|
|
|
persistentStateChange.getStateIdentifier,
|
2016-04-14 02:31:33 +03:00
|
|
|
// timeout field is deprecated, left for backward compatibility. timeoutNanos is used instead.
|
|
|
|
|
if (persistentStateChange.hasTimeoutNanos) Some(Duration.fromNanos(persistentStateChange.getTimeoutNanos))
|
|
|
|
|
else if (persistentStateChange.hasTimeout) Some(Duration(persistentStateChange.getTimeout).asInstanceOf[duration.FiniteDuration])
|
|
|
|
|
else None)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def persistentFSMSnapshot(persistentFSMSnapshot: mf.PersistentFSMSnapshot): PersistentFSMSnapshot[Any] = {
|
|
|
|
|
PersistentFSMSnapshot(
|
|
|
|
|
persistentFSMSnapshot.getStateIdentifier,
|
|
|
|
|
payload(persistentFSMSnapshot.getData),
|
|
|
|
|
if (persistentFSMSnapshot.hasTimeoutNanos) Some(Duration.fromNanos(persistentFSMSnapshot.getTimeoutNanos)) else None)
|
2014-11-09 14:12:36 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-23 21:01:36 +02:00
|
|
|
private def atomicWriteBuilder(a: AtomicWrite) = {
|
|
|
|
|
val builder = mf.AtomicWrite.newBuilder
|
|
|
|
|
a.payload.foreach { p ⇒
|
|
|
|
|
builder.addPayload(persistentMessageBuilder(p))
|
|
|
|
|
}
|
|
|
|
|
builder
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-07 10:45:02 +01:00
|
|
|
private def persistentMessageBuilder(persistent: PersistentRepr) = {
|
2015-06-23 21:01:36 +02:00
|
|
|
val builder = mf.PersistentMessage.newBuilder
|
2013-10-09 13:11:53 +02:00
|
|
|
|
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))
|
2015-09-04 01:38:26 +02:00
|
|
|
if (persistent.manifest != PersistentRepr.Undefined) builder.setManifest(persistent.manifest)
|
2013-10-09 13:11:53 +02:00
|
|
|
|
|
|
|
|
builder.setPayload(persistentPayloadBuilder(persistent.payload.asInstanceOf[AnyRef]))
|
|
|
|
|
builder.setSequenceNr(persistent.sequenceNr)
|
2015-06-25 07:44:52 +02:00
|
|
|
// deleted is not used in new records from 2.4
|
2015-06-25 11:38:51 +02:00
|
|
|
if (persistent.writerUuid != Undefined) builder.setWriterUuid(persistent.writerUuid)
|
2013-10-09 13:11:53 +02:00
|
|
|
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)
|
2015-06-23 21:01:36 +02:00
|
|
|
val builder = mf.PersistentPayload.newBuilder()
|
2013-10-09 13:11:53 +02:00
|
|
|
|
2018-04-12 19:58:13 +03:00
|
|
|
val ms = Serializers.manifestFor(serializer, payload)
|
|
|
|
|
if (ms.nonEmpty) builder.setPayloadManifest(ByteString.copyFromUtf8(ms))
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-21 16:59:04 +02:00
|
|
|
val oldInfo = Serialization.currentTransportInformation.value
|
|
|
|
|
try {
|
|
|
|
|
if (oldInfo eq null)
|
|
|
|
|
Serialization.currentTransportInformation.value = system.provider.serializationInformation
|
|
|
|
|
payloadBuilder()
|
|
|
|
|
} finally Serialization.currentTransportInformation.value = oldInfo
|
2013-10-09 13:11:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// fromBinary helpers
|
|
|
|
|
//
|
|
|
|
|
|
2015-06-23 21:01:36 +02:00
|
|
|
private def persistent(persistentMessage: mf.PersistentMessage): PersistentRepr = {
|
2013-11-07 10:45:02 +01:00
|
|
|
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,
|
2015-06-25 07:44:52 +02:00
|
|
|
if (persistentMessage.hasDeleted) persistentMessage.getDeleted else false,
|
2015-06-25 11:38:51 +02:00
|
|
|
if (persistentMessage.hasSender) system.provider.resolveActorRef(persistentMessage.getSender) else Actor.noSender,
|
|
|
|
|
if (persistentMessage.hasWriterUuid) persistentMessage.getWriterUuid else Undefined)
|
2013-10-09 13:11:53 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-23 21:01:36 +02:00
|
|
|
private def atomicWrite(atomicWrite: mf.AtomicWrite): AtomicWrite = {
|
|
|
|
|
import scala.collection.JavaConverters._
|
|
|
|
|
AtomicWrite(atomicWrite.getPayloadList.asScala.map(persistent)(collection.breakOut))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private def payload(persistentPayload: mf.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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|