add docs about how to serialize ActorRefs
- scala & java samples of how to obtain the correct address to inject when calling ActorPath.toStringWithAddress
This commit is contained in:
parent
d8bb688ece
commit
7d342e5c96
4 changed files with 233 additions and 27 deletions
|
|
@ -7,6 +7,7 @@ import org.junit.Test;
|
|||
import static org.junit.Assert.*;
|
||||
//#imports
|
||||
import akka.actor.*;
|
||||
import akka.remote.RemoteActorRefProvider;
|
||||
import akka.serialization.*;
|
||||
import com.typesafe.config.*;
|
||||
|
||||
|
|
@ -78,32 +79,118 @@ public class SerializationDocTestBase {
|
|||
//#actorref-serializer
|
||||
theActorSystem.shutdown();
|
||||
}
|
||||
|
||||
//#external-address
|
||||
public static class ExternalAddressExt implements Extension {
|
||||
private final ExtendedActorSystem system;
|
||||
|
||||
public ExternalAddressExt(ExtendedActorSystem system) {
|
||||
this.system = system;
|
||||
}
|
||||
|
||||
@Test public void demonstrateTheProgrammaticAPI() {
|
||||
//#programmatic
|
||||
ActorSystem system = ActorSystem.create("example");
|
||||
|
||||
// Get the Serialization Extension
|
||||
Serialization serialization = SerializationExtension.get(system);
|
||||
|
||||
// Have something to serialize
|
||||
String original = "woohoo";
|
||||
|
||||
// Find the Serializer for it
|
||||
Serializer serializer = serialization.findSerializerFor(original);
|
||||
|
||||
// Turn it into bytes
|
||||
byte[] bytes = serializer.toBinary(original);
|
||||
|
||||
// Turn it back into an object,
|
||||
// the nulls are for the class manifest and for the classloader
|
||||
String back = (String)serializer.fromBinary(bytes);
|
||||
|
||||
// Voilá!
|
||||
assertEquals(original, back);
|
||||
|
||||
//#programmatic
|
||||
system.shutdown();
|
||||
public Address getAddressFor(Address remoteAddress) {
|
||||
final scala.Option<Address> optAddr = system.provider()
|
||||
.getExternalAddressFor(remoteAddress);
|
||||
if (optAddr.isDefined()) {
|
||||
return optAddr.get();
|
||||
} else {
|
||||
throw new UnsupportedOperationException(
|
||||
"cannot send to remote address " + remoteAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExternalAddress extends
|
||||
AbstractExtensionId<ExternalAddressExt> implements ExtensionIdProvider {
|
||||
public static final ExternalAddress ID = new ExternalAddress();
|
||||
|
||||
public ExternalAddress lookup() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
public ExternalAddressExt createExtension(ExtendedActorSystem system) {
|
||||
return new ExternalAddressExt(system);
|
||||
}
|
||||
}
|
||||
|
||||
//#external-address
|
||||
|
||||
public void demonstrateExternalAddress() {
|
||||
// this is not meant to be run, only to be compiled
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final Address remoteAddr = new Address("", "");
|
||||
// #external-address
|
||||
final Address addr = ExternalAddress.ID.get(system).getAddressFor(remoteAddr);
|
||||
// #external-address
|
||||
}
|
||||
|
||||
//#external-address-default
|
||||
public static class DefaultAddressExt implements Extension {
|
||||
private final ExtendedActorSystem system;
|
||||
|
||||
public DefaultAddressExt(ExtendedActorSystem system) {
|
||||
this.system = system;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
final ActorRefProvider provider = system.provider();
|
||||
if (provider instanceof RemoteActorRefProvider) {
|
||||
return ((RemoteActorRefProvider) provider).transport().address();
|
||||
} else {
|
||||
throw new UnsupportedOperationException("need RemoteActorRefProvider");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class DefaultAddress extends
|
||||
AbstractExtensionId<DefaultAddressExt> implements ExtensionIdProvider {
|
||||
public static final DefaultAddress ID = new DefaultAddress();
|
||||
|
||||
public DefaultAddress lookup() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
public DefaultAddressExt createExtension(ExtendedActorSystem system) {
|
||||
return new DefaultAddressExt(system);
|
||||
}
|
||||
}
|
||||
|
||||
//#external-address-default
|
||||
|
||||
public void demonstrateDefaultAddress() {
|
||||
// this is not meant to be run, only to be compiled
|
||||
final ActorSystem system = ActorSystem.create();
|
||||
final Address remoteAddr = new Address("", "");
|
||||
// #external-address-default
|
||||
final Address addr = DefaultAddress.ID.get(system).getAddress();
|
||||
// #external-address-default
|
||||
}
|
||||
|
||||
@Test
|
||||
public void demonstrateTheProgrammaticAPI() {
|
||||
// #programmatic
|
||||
ActorSystem system = ActorSystem.create("example");
|
||||
|
||||
// Get the Serialization Extension
|
||||
Serialization serialization = SerializationExtension.get(system);
|
||||
|
||||
// Have something to serialize
|
||||
String original = "woohoo";
|
||||
|
||||
// Find the Serializer for it
|
||||
Serializer serializer = serialization.findSerializerFor(original);
|
||||
|
||||
// Turn it into bytes
|
||||
byte[] bytes = serializer.toBinary(original);
|
||||
|
||||
// Turn it back into an object,
|
||||
// the nulls are for the class manifest and for the classloader
|
||||
String back = (String) serializer.fromBinary(bytes);
|
||||
|
||||
// Voilá!
|
||||
assertEquals(original, back);
|
||||
|
||||
// #programmatic
|
||||
system.shutdown();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,47 @@ you might want to know how to serialize and deserialize them properly, here's th
|
|||
.. includecode:: code/akka/docs/serialization/SerializationDocTestBase.java
|
||||
:include: imports,actorref-serializer
|
||||
|
||||
.. note::
|
||||
|
||||
``ActorPath.toStringWithAddress`` only differs from ``toString`` if the
|
||||
address does not already have ``host`` and ``port`` components, i.e. it only
|
||||
inserts address information for local addresses.
|
||||
|
||||
This assumes that serialization happens in the context of sending a message
|
||||
through the remote transport. There are other uses of serialization, though,
|
||||
e.g. storing actor references outside of an actor application (database,
|
||||
durable mailbox, etc.). In this case, it is important to keep in mind that the
|
||||
address part of an actor’s path determines how that actor is communicated with.
|
||||
Storing a local actor path might be the right choice if the retrieval happens
|
||||
in the same logical context, but it is not enough when deserializing it on a
|
||||
different network host: for that it would need to include the system’s remote
|
||||
transport address. An actor system is not limited to having just one remote
|
||||
transport per se, which makes this question a bit more interesting.
|
||||
|
||||
In the general case, the local address to be used depends on the type of remote
|
||||
address which shall be the recipient of the serialized information. Use
|
||||
:meth:`ActorRefProvider.getExternalAddressFor(remoteAddr)` to query the system
|
||||
for the appropriate address to use when sending to ``remoteAddr``:
|
||||
|
||||
.. includecode:: code/akka/docs/serialization/SerializationDocTestBase.java
|
||||
:include: external-address
|
||||
|
||||
This requires that you know at least which type of address will be supported by
|
||||
the system which will deserialize the resulting actor reference; if you have no
|
||||
concrete address handy you can create a dummy one for the right protocol using
|
||||
``new Address(protocol, "", "", 0)`` (assuming that the actual transport used is as
|
||||
lenient as Akka’s RemoteActorRefProvider).
|
||||
|
||||
There is a possible simplification available if you are just using the default
|
||||
:class:`NettyRemoteTransport` with the :meth:`RemoteActorRefProvider`, which is
|
||||
enabled by the fact that this combination has just a single remote address:
|
||||
|
||||
.. includecode:: code/akka/docs/serialization/SerializationDocTestBase.java
|
||||
:include: external-address-default
|
||||
|
||||
This solution has to be adapted once other providers are used (like the planned
|
||||
extensions for clustering).
|
||||
|
||||
Deep serialization of Actors
|
||||
----------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,17 @@ package docs.serialization
|
|||
|
||||
import org.scalatest.matchers.MustMatchers
|
||||
import akka.testkit._
|
||||
import akka.actor.{ ActorRef, ActorSystem }
|
||||
|
||||
//#imports
|
||||
import akka.actor.{ ActorRef, ActorSystem }
|
||||
import akka.serialization._
|
||||
import com.typesafe.config.ConfigFactory
|
||||
|
||||
//#imports
|
||||
import akka.actor.ExtensionKey
|
||||
import akka.actor.ExtendedActorSystem
|
||||
import akka.actor.Extension
|
||||
import akka.actor.Address
|
||||
import akka.remote.RemoteActorRefProvider
|
||||
|
||||
//#my-own-serializer
|
||||
class MyOwnSerializer extends Serializer {
|
||||
|
|
@ -176,5 +180,38 @@ class SerializationDocSpec extends AkkaSpec {
|
|||
val deserializedActorRef = theActorSystem actorFor identifier
|
||||
// Then just use the ActorRef
|
||||
//#actorref-serializer
|
||||
|
||||
//#external-address
|
||||
object ExternalAddress extends ExtensionKey[ExternalAddressExt]
|
||||
|
||||
class ExternalAddressExt(system: ExtendedActorSystem) extends Extension {
|
||||
def addressFor(remoteAddr: Address): Address =
|
||||
system.provider.getExternalAddressFor(remoteAddr) getOrElse
|
||||
(throw new UnsupportedOperationException("cannot send to " + remoteAddr))
|
||||
}
|
||||
|
||||
def serializeTo(ref: ActorRef, remote: Address): String =
|
||||
ref.path.toStringWithAddress(ExternalAddress(theActorSystem).addressFor(remote))
|
||||
//#external-address
|
||||
}
|
||||
|
||||
"demonstrate how to do default Akka serialization of ActorRef" in {
|
||||
val theActorSystem: ActorSystem = system
|
||||
|
||||
//#external-address-default
|
||||
object ExternalAddress extends ExtensionKey[ExternalAddressExt]
|
||||
|
||||
class ExternalAddressExt(system: ExtendedActorSystem) extends Extension {
|
||||
def addressForAkka: Address = system.provider match {
|
||||
case r: RemoteActorRefProvider ⇒ r.transport.address
|
||||
case _ ⇒
|
||||
throw new UnsupportedOperationException(
|
||||
"this method requires the RemoteActorRefProvider to be configured")
|
||||
}
|
||||
}
|
||||
|
||||
def serializeAkkaDefault(ref: ActorRef): String =
|
||||
ref.path.toStringWithAddress(ExternalAddress(theActorSystem).addressForAkka)
|
||||
//#external-address-default
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,6 +107,47 @@ you might want to know how to serialize and deserialize them properly, here's th
|
|||
.. includecode:: code/akka/docs/serialization/SerializationDocSpec.scala
|
||||
:include: imports,actorref-serializer
|
||||
|
||||
.. note::
|
||||
|
||||
``ActorPath.toStringWithAddress`` only differs from ``toString`` if the
|
||||
address does not already have ``host`` and ``port`` components, i.e. it only
|
||||
inserts address information for local addresses.
|
||||
|
||||
This assumes that serialization happens in the context of sending a message
|
||||
through the remote transport. There are other uses of serialization, though,
|
||||
e.g. storing actor references outside of an actor application (database,
|
||||
durable mailbox, etc.). In this case, it is important to keep in mind that the
|
||||
address part of an actor’s path determines how that actor is communicated with.
|
||||
Storing a local actor path might be the right choice if the retrieval happens
|
||||
in the same logical context, but it is not enough when deserializing it on a
|
||||
different network host: for that it would need to include the system’s remote
|
||||
transport address. An actor system is not limited to having just one remote
|
||||
transport per se, which makes this question a bit more interesting.
|
||||
|
||||
In the general case, the local address to be used depends on the type of remote
|
||||
address which shall be the recipient of the serialized information. Use
|
||||
:meth:`ActorRefProvider.getExternalAddressFor(remoteAddr)` to query the system
|
||||
for the appropriate address to use when sending to ``remoteAddr``:
|
||||
|
||||
.. includecode:: code/akka/docs/serialization/SerializationDocSpec.scala
|
||||
:include: external-address
|
||||
|
||||
This requires that you know at least which type of address will be supported by
|
||||
the system which will deserialize the resulting actor reference; if you have no
|
||||
concrete address handy you can create a dummy one for the right protocol using
|
||||
``Address(protocol, "", "", 0)`` (assuming that the actual transport used is as
|
||||
lenient as Akka’s RemoteActorRefProvider).
|
||||
|
||||
There is a possible simplification available if you are just using the default
|
||||
:class:`NettyRemoteTransport` with the :meth:`RemoteActorRefProvider`, which is
|
||||
enabled by the fact that this combination has just a single remote address:
|
||||
|
||||
.. includecode:: code/akka/docs/serialization/SerializationDocSpec.scala
|
||||
:include: external-address-default
|
||||
|
||||
This solution has to be adapted once other providers are used (like the planned
|
||||
extensions for clustering).
|
||||
|
||||
Deep serialization of Actors
|
||||
----------------------------
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue