Formatting java codes with sbt-java-formatter.
This commit is contained in:
parent
27500001ea
commit
998c5a9285
401 changed files with 19750 additions and 17450 deletions
|
|
@ -6,9 +6,5 @@ package jdocs;
|
|||
|
||||
import org.scalatest.junit.JUnitSuite;
|
||||
|
||||
/**
|
||||
* Base class for all runnable example tests written in Java
|
||||
*/
|
||||
public abstract class AbstractJavaTest extends JUnitSuite {
|
||||
|
||||
}
|
||||
/** Base class for all runnable example tests written in Java */
|
||||
public abstract class AbstractJavaTest extends JUnitSuite {}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -12,11 +12,13 @@ class BlockingActor extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Integer.class, i -> {
|
||||
Thread.sleep(5000); //block for 5 seconds, representing blocking I/O, etc
|
||||
System.out.println("Blocking operation finished: " + i);
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
Integer.class,
|
||||
i -> {
|
||||
Thread.sleep(5000); // block for 5 seconds, representing blocking I/O, etc
|
||||
System.out.println("Blocking operation finished: " + i);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
// #blocking-in-actor
|
||||
// #blocking-in-actor
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public class BlockingDispatcherTest {
|
|||
Thread.sleep(5000 * 6);
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
//swallow the exception
|
||||
// swallow the exception
|
||||
} finally {
|
||||
system.terminate();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,15 +16,20 @@ class BlockingFutureActor extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Integer.class, i -> {
|
||||
System.out.println("Calling blocking Future: " + i);
|
||||
Future<Integer> f = Futures.future(() -> {
|
||||
Thread.sleep(5000);
|
||||
System.out.println("Blocking future finished: " + i);
|
||||
return i;
|
||||
}, ec);
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
Integer.class,
|
||||
i -> {
|
||||
System.out.println("Calling blocking Future: " + i);
|
||||
Future<Integer> f =
|
||||
Futures.future(
|
||||
() -> {
|
||||
Thread.sleep(5000);
|
||||
System.out.println("Blocking future finished: " + i);
|
||||
return i;
|
||||
},
|
||||
ec);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
// #blocking-in-future
|
||||
// #blocking-in-future
|
||||
|
|
|
|||
|
|
@ -4,19 +4,18 @@
|
|||
|
||||
package jdocs.actor;
|
||||
|
||||
//#bytebufserializer-with-manifest
|
||||
// #bytebufserializer-with-manifest
|
||||
import akka.serialization.ByteBufferSerializer;
|
||||
import akka.serialization.SerializerWithStringManifest;
|
||||
|
||||
//#bytebufserializer-with-manifest
|
||||
// #bytebufserializer-with-manifest
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class ByteBufferSerializerDocTest {
|
||||
|
||||
|
||||
static //#bytebufserializer-with-manifest
|
||||
static // #bytebufserializer-with-manifest
|
||||
class ExampleByteBufSerializer extends SerializerWithStringManifest
|
||||
implements ByteBufferSerializer {
|
||||
implements ByteBufferSerializer {
|
||||
|
||||
@Override
|
||||
public int identifier() {
|
||||
|
|
@ -56,24 +55,21 @@ public class ByteBufferSerializerDocTest {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
//#bytebufserializer-with-manifest
|
||||
|
||||
// #bytebufserializer-with-manifest
|
||||
|
||||
static class OnlyForDocInclude {
|
||||
static
|
||||
//#ByteBufferSerializer-interface
|
||||
// #ByteBufferSerializer-interface
|
||||
interface ByteBufferSerializer {
|
||||
/**
|
||||
* Serializes the given object into the `ByteBuffer`.
|
||||
*/
|
||||
/** Serializes the given object into the `ByteBuffer`. */
|
||||
void toBinary(Object o, ByteBuffer buf);
|
||||
|
||||
|
||||
/**
|
||||
* Produces an object from a `ByteBuffer`, with an optional type-hint;
|
||||
* the class should be loaded using ActorSystem.dynamicAccess.
|
||||
* Produces an object from a `ByteBuffer`, with an optional type-hint; the class should be
|
||||
* loaded using ActorSystem.dynamicAccess.
|
||||
*/
|
||||
Object fromBinary(ByteBuffer buf, String manifest);
|
||||
}
|
||||
//#ByteBufferSerializer-interface
|
||||
// #ByteBufferSerializer-interface
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,31 +15,33 @@ import akka.actor.ActorRef;
|
|||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
|
||||
//#import
|
||||
// #import
|
||||
import akka.actor.Actor;
|
||||
import akka.actor.IndirectActorProducer;
|
||||
//#import
|
||||
// #import
|
||||
|
||||
public class DependencyInjectionDocTest extends AbstractJavaTest {
|
||||
|
||||
public static class TheActor extends AbstractActor {
|
||||
|
||||
final String s;
|
||||
|
||||
|
||||
public TheActor(String s) {
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(String.class, msg -> {
|
||||
getSender().tell(s, getSelf());
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
String.class,
|
||||
msg -> {
|
||||
getSender().tell(s, getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ActorSystem system = null;
|
||||
|
||||
@BeforeClass
|
||||
|
|
@ -52,47 +54,48 @@ public class DependencyInjectionDocTest extends AbstractJavaTest {
|
|||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
||||
//this is just to make the test below a tiny fraction nicer
|
||||
// this is just to make the test below a tiny fraction nicer
|
||||
private ActorSystem getContext() {
|
||||
return system;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
//#creating-indirectly
|
||||
// #creating-indirectly
|
||||
class DependencyInjector implements IndirectActorProducer {
|
||||
final Object applicationContext;
|
||||
final String beanName;
|
||||
|
||||
|
||||
public DependencyInjector(Object applicationContext, String beanName) {
|
||||
this.applicationContext = applicationContext;
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class<? extends Actor> actorClass() {
|
||||
return TheActor.class;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TheActor produce() {
|
||||
TheActor result;
|
||||
//#obtain-fresh-Actor-instance-from-DI-framework
|
||||
// #obtain-fresh-Actor-instance-from-DI-framework
|
||||
result = new TheActor((String) applicationContext);
|
||||
//#obtain-fresh-Actor-instance-from-DI-framework
|
||||
// #obtain-fresh-Actor-instance-from-DI-framework
|
||||
return result;
|
||||
}
|
||||
}
|
||||
//#creating-indirectly
|
||||
|
||||
// #creating-indirectly
|
||||
|
||||
@Test
|
||||
public void indirectActorOf() {
|
||||
final String applicationContext = "...";
|
||||
//#creating-indirectly
|
||||
|
||||
final ActorRef myActor = getContext().actorOf(
|
||||
Props.create(DependencyInjector.class, applicationContext, "TheActor"),
|
||||
"TheActor");
|
||||
//#creating-indirectly
|
||||
// #creating-indirectly
|
||||
|
||||
final ActorRef myActor =
|
||||
getContext()
|
||||
.actorOf(
|
||||
Props.create(DependencyInjector.class, applicationContext, "TheActor"), "TheActor");
|
||||
// #creating-indirectly
|
||||
new TestKit(system) {
|
||||
{
|
||||
myActor.tell("hello", getRef());
|
||||
|
|
@ -100,5 +103,4 @@ public class DependencyInjectionDocTest extends AbstractJavaTest {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
package jdocs.actor;
|
||||
|
||||
//#all
|
||||
//#imports
|
||||
// #all
|
||||
// #imports
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
|
@ -33,20 +33,19 @@ import static jdocs.actor.FaultHandlingDocSample.CounterServiceApi.*;
|
|||
import static jdocs.actor.FaultHandlingDocSample.CounterApi.*;
|
||||
import static jdocs.actor.FaultHandlingDocSample.StorageApi.*;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
|
||||
public class FaultHandlingDocSample {
|
||||
|
||||
/**
|
||||
* Runs the sample
|
||||
*/
|
||||
/** Runs the sample */
|
||||
public static void main(String[] args) {
|
||||
Config config = ConfigFactory.parseString(
|
||||
"akka.loglevel = \"DEBUG\"\n" +
|
||||
"akka.actor.debug {\n" +
|
||||
" receive = on\n" +
|
||||
" lifecycle = on\n" +
|
||||
"}\n");
|
||||
Config config =
|
||||
ConfigFactory.parseString(
|
||||
"akka.loglevel = \"DEBUG\"\n"
|
||||
+ "akka.actor.debug {\n"
|
||||
+ " receive = on\n"
|
||||
+ " lifecycle = on\n"
|
||||
+ "}\n");
|
||||
|
||||
ActorSystem system = ActorSystem.create("FaultToleranceSample", config);
|
||||
ActorRef worker = system.actorOf(Props.create(Worker.class), "worker");
|
||||
|
|
@ -58,8 +57,7 @@ public class FaultHandlingDocSample {
|
|||
}
|
||||
|
||||
/**
|
||||
* Listens on progress from the worker and shuts down the system when enough
|
||||
* work has been done.
|
||||
* Listens on progress from the worker and shuts down the system when enough work has been done.
|
||||
*/
|
||||
public static class Listener extends AbstractLoggingActor {
|
||||
|
||||
|
|
@ -72,23 +70,30 @@ public class FaultHandlingDocSample {
|
|||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return LoggingReceive.create(receiveBuilder().
|
||||
match(Progress.class, progress -> {
|
||||
log().info("Current progress: {} %", progress.percent);
|
||||
if (progress.percent >= 100.0) {
|
||||
log().info("That's all, shutting down");
|
||||
getContext().getSystem().terminate();
|
||||
}
|
||||
}).
|
||||
matchEquals(ReceiveTimeout.getInstance(), x -> {
|
||||
// No progress within 15 seconds, ServiceUnavailable
|
||||
log().error("Shutting down due to unavailable service");
|
||||
getContext().getSystem().terminate();
|
||||
}).build(), getContext());
|
||||
return LoggingReceive.create(
|
||||
receiveBuilder()
|
||||
.match(
|
||||
Progress.class,
|
||||
progress -> {
|
||||
log().info("Current progress: {} %", progress.percent);
|
||||
if (progress.percent >= 100.0) {
|
||||
log().info("That's all, shutting down");
|
||||
getContext().getSystem().terminate();
|
||||
}
|
||||
})
|
||||
.matchEquals(
|
||||
ReceiveTimeout.getInstance(),
|
||||
x -> {
|
||||
// No progress within 15 seconds, ServiceUnavailable
|
||||
log().error("Shutting down due to unavailable service");
|
||||
getContext().getSystem().terminate();
|
||||
})
|
||||
.build(),
|
||||
getContext());
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
// #messages
|
||||
public interface WorkerApi {
|
||||
public static final Object Start = "Start";
|
||||
public static final Object Do = "Do";
|
||||
|
|
@ -106,12 +111,11 @@ public class FaultHandlingDocSample {
|
|||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
// #messages
|
||||
|
||||
/**
|
||||
* Worker performs some work when it receives the Start message. It will
|
||||
* continuously notify the sender of the Start message of current Progress.
|
||||
* The Worker supervise the CounterService.
|
||||
* Worker performs some work when it receives the Start message. It will continuously notify the
|
||||
* sender of the Start message of current Progress. The Worker supervise the CounterService.
|
||||
*/
|
||||
public static class Worker extends AbstractLoggingActor {
|
||||
final Timeout askTimeout = Timeout.create(Duration.ofSeconds(5));
|
||||
|
|
@ -119,15 +123,16 @@ public class FaultHandlingDocSample {
|
|||
// The sender of the initial Start message will continuously be notified
|
||||
// about progress
|
||||
ActorRef progressListener;
|
||||
final ActorRef counterService = getContext().actorOf(
|
||||
Props.create(CounterService.class), "counter");
|
||||
final ActorRef counterService =
|
||||
getContext().actorOf(Props.create(CounterService.class), "counter");
|
||||
final int totalCount = 51;
|
||||
|
||||
// Stop the CounterService child if it throws ServiceUnavailable
|
||||
private static final SupervisorStrategy strategy =
|
||||
new OneForOneStrategy(DeciderBuilder.
|
||||
match(ServiceUnavailable.class, e -> stop()).
|
||||
matchAny(o -> escalate()).build());
|
||||
new OneForOneStrategy(
|
||||
DeciderBuilder.match(ServiceUnavailable.class, e -> stop())
|
||||
.matchAny(o -> escalate())
|
||||
.build());
|
||||
|
||||
@Override
|
||||
public SupervisorStrategy supervisorStrategy() {
|
||||
|
|
@ -136,32 +141,50 @@ public class FaultHandlingDocSample {
|
|||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return LoggingReceive.create(receiveBuilder().
|
||||
matchEquals(Start, x -> progressListener == null, x -> {
|
||||
progressListener = getSender();
|
||||
getContext().getSystem().scheduler().schedule(
|
||||
Duration.ZERO, Duration.ofSeconds(1L), getSelf(), Do,
|
||||
getContext().getDispatcher(), null
|
||||
);
|
||||
}).
|
||||
matchEquals(Do, x -> {
|
||||
counterService.tell(new Increment(1), getSelf());
|
||||
counterService.tell(new Increment(1), getSelf());
|
||||
counterService.tell(new Increment(1), getSelf());
|
||||
// Send current progress to the initial sender
|
||||
pipe(Patterns.ask(counterService, GetCurrentCount, askTimeout)
|
||||
.mapTo(classTag(CurrentCount.class))
|
||||
.map(new Mapper<CurrentCount, Progress>() {
|
||||
public Progress apply(CurrentCount c) {
|
||||
return new Progress(100.0 * c.count / totalCount);
|
||||
}
|
||||
}, getContext().dispatcher()), getContext().dispatcher())
|
||||
.to(progressListener);
|
||||
}).build(), getContext());
|
||||
return LoggingReceive.create(
|
||||
receiveBuilder()
|
||||
.matchEquals(
|
||||
Start,
|
||||
x -> progressListener == null,
|
||||
x -> {
|
||||
progressListener = getSender();
|
||||
getContext()
|
||||
.getSystem()
|
||||
.scheduler()
|
||||
.schedule(
|
||||
Duration.ZERO,
|
||||
Duration.ofSeconds(1L),
|
||||
getSelf(),
|
||||
Do,
|
||||
getContext().getDispatcher(),
|
||||
null);
|
||||
})
|
||||
.matchEquals(
|
||||
Do,
|
||||
x -> {
|
||||
counterService.tell(new Increment(1), getSelf());
|
||||
counterService.tell(new Increment(1), getSelf());
|
||||
counterService.tell(new Increment(1), getSelf());
|
||||
// Send current progress to the initial sender
|
||||
pipe(
|
||||
Patterns.ask(counterService, GetCurrentCount, askTimeout)
|
||||
.mapTo(classTag(CurrentCount.class))
|
||||
.map(
|
||||
new Mapper<CurrentCount, Progress>() {
|
||||
public Progress apply(CurrentCount c) {
|
||||
return new Progress(100.0 * c.count / totalCount);
|
||||
}
|
||||
},
|
||||
getContext().dispatcher()),
|
||||
getContext().dispatcher())
|
||||
.to(progressListener);
|
||||
})
|
||||
.build(),
|
||||
getContext());
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
// #messages
|
||||
public interface CounterServiceApi {
|
||||
|
||||
public static final Object GetCurrentCount = "GetCurrentCount";
|
||||
|
|
@ -194,19 +217,18 @@ public class FaultHandlingDocSample {
|
|||
|
||||
public static class ServiceUnavailable extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ServiceUnavailable(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//#messages
|
||||
// #messages
|
||||
|
||||
/**
|
||||
* Adds the value received in Increment message to a persistent counter.
|
||||
* Replies with CurrentCount when it is asked for CurrentCount. CounterService
|
||||
* supervise Storage and Counter.
|
||||
* Adds the value received in Increment message to a persistent counter. Replies with CurrentCount
|
||||
* when it is asked for CurrentCount. CounterService supervise Storage and Counter.
|
||||
*/
|
||||
public static class CounterService extends AbstractLoggingActor {
|
||||
|
||||
|
|
@ -232,9 +254,12 @@ public class FaultHandlingDocSample {
|
|||
// Restart the storage child when StorageException is thrown.
|
||||
// After 3 restarts within 5 seconds it will be stopped.
|
||||
private static final SupervisorStrategy strategy =
|
||||
new OneForOneStrategy(3, Duration.ofSeconds(5), DeciderBuilder.
|
||||
match(StorageException.class, e -> restart()).
|
||||
matchAny(o -> escalate()).build());
|
||||
new OneForOneStrategy(
|
||||
3,
|
||||
Duration.ofSeconds(5),
|
||||
DeciderBuilder.match(StorageException.class, e -> restart())
|
||||
.matchAny(o -> escalate())
|
||||
.build());
|
||||
|
||||
@Override
|
||||
public SupervisorStrategy supervisorStrategy() {
|
||||
|
|
@ -247,58 +272,75 @@ public class FaultHandlingDocSample {
|
|||
}
|
||||
|
||||
/**
|
||||
* The child storage is restarted in case of failure, but after 3 restarts,
|
||||
* and still failing it will be stopped. Better to back-off than
|
||||
* continuously failing. When it has been stopped we will schedule a
|
||||
* Reconnect after a delay. Watch the child so we receive Terminated message
|
||||
* The child storage is restarted in case of failure, but after 3 restarts, and still failing it
|
||||
* will be stopped. Better to back-off than continuously failing. When it has been stopped we
|
||||
* will schedule a Reconnect after a delay. Watch the child so we receive Terminated message
|
||||
* when it has been terminated.
|
||||
*/
|
||||
void initStorage() {
|
||||
storage = getContext().watch(getContext().actorOf(
|
||||
Props.create(Storage.class), "storage"));
|
||||
storage = getContext().watch(getContext().actorOf(Props.create(Storage.class), "storage"));
|
||||
// Tell the counter, if any, to use the new storage
|
||||
if (counter != null)
|
||||
counter.tell(new UseStorage(storage), getSelf());
|
||||
if (counter != null) counter.tell(new UseStorage(storage), getSelf());
|
||||
// We need the initial value to be able to operate
|
||||
storage.tell(new Get(key), getSelf());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return LoggingReceive.create(receiveBuilder().
|
||||
match(Entry.class, entry -> entry.key.equals(key) && counter == null, entry -> {
|
||||
// Reply from Storage of the initial value, now we can create the Counter
|
||||
final long value = entry.value;
|
||||
counter = getContext().actorOf(Props.create(Counter.class, key, value));
|
||||
// Tell the counter to use current storage
|
||||
counter.tell(new UseStorage(storage), getSelf());
|
||||
// and send the buffered backlog to the counter
|
||||
for (SenderMsgPair each : backlog) {
|
||||
counter.tell(each.msg, each.sender);
|
||||
}
|
||||
backlog.clear();
|
||||
}).
|
||||
match(Increment.class, increment -> {
|
||||
forwardOrPlaceInBacklog(increment);
|
||||
}).
|
||||
matchEquals(GetCurrentCount, gcc -> {
|
||||
forwardOrPlaceInBacklog(gcc);
|
||||
}).
|
||||
match(Terminated.class, o -> {
|
||||
// After 3 restarts the storage child is stopped.
|
||||
// We receive Terminated because we watch the child, see initStorage.
|
||||
storage = null;
|
||||
// Tell the counter that there is no storage for the moment
|
||||
counter.tell(new UseStorage(null), getSelf());
|
||||
// Try to re-establish storage after while
|
||||
getContext().getSystem().scheduler().scheduleOnce(
|
||||
Duration.ofSeconds(10), getSelf(), Reconnect,
|
||||
getContext().getDispatcher(), null);
|
||||
}).
|
||||
matchEquals(Reconnect, o -> {
|
||||
// Re-establish storage after the scheduled delay
|
||||
initStorage();
|
||||
}).build(), getContext());
|
||||
return LoggingReceive.create(
|
||||
receiveBuilder()
|
||||
.match(
|
||||
Entry.class,
|
||||
entry -> entry.key.equals(key) && counter == null,
|
||||
entry -> {
|
||||
// Reply from Storage of the initial value, now we can create the Counter
|
||||
final long value = entry.value;
|
||||
counter = getContext().actorOf(Props.create(Counter.class, key, value));
|
||||
// Tell the counter to use current storage
|
||||
counter.tell(new UseStorage(storage), getSelf());
|
||||
// and send the buffered backlog to the counter
|
||||
for (SenderMsgPair each : backlog) {
|
||||
counter.tell(each.msg, each.sender);
|
||||
}
|
||||
backlog.clear();
|
||||
})
|
||||
.match(
|
||||
Increment.class,
|
||||
increment -> {
|
||||
forwardOrPlaceInBacklog(increment);
|
||||
})
|
||||
.matchEquals(
|
||||
GetCurrentCount,
|
||||
gcc -> {
|
||||
forwardOrPlaceInBacklog(gcc);
|
||||
})
|
||||
.match(
|
||||
Terminated.class,
|
||||
o -> {
|
||||
// After 3 restarts the storage child is stopped.
|
||||
// We receive Terminated because we watch the child, see initStorage.
|
||||
storage = null;
|
||||
// Tell the counter that there is no storage for the moment
|
||||
counter.tell(new UseStorage(null), getSelf());
|
||||
// Try to re-establish storage after while
|
||||
getContext()
|
||||
.getSystem()
|
||||
.scheduler()
|
||||
.scheduleOnce(
|
||||
Duration.ofSeconds(10),
|
||||
getSelf(),
|
||||
Reconnect,
|
||||
getContext().getDispatcher(),
|
||||
null);
|
||||
})
|
||||
.matchEquals(
|
||||
Reconnect,
|
||||
o -> {
|
||||
// Re-establish storage after the scheduled delay
|
||||
initStorage();
|
||||
})
|
||||
.build(),
|
||||
getContext());
|
||||
}
|
||||
|
||||
void forwardOrPlaceInBacklog(Object msg) {
|
||||
|
|
@ -307,8 +349,7 @@ public class FaultHandlingDocSample {
|
|||
// to the counter when it is initialized.
|
||||
if (counter == null) {
|
||||
if (backlog.size() >= MAX_BACKLOG)
|
||||
throw new ServiceUnavailable("CounterService not available," +
|
||||
" lack of initial value");
|
||||
throw new ServiceUnavailable("CounterService not available," + " lack of initial value");
|
||||
backlog.add(new SenderMsgPair(getSender(), msg));
|
||||
} else {
|
||||
counter.forward(msg, getContext());
|
||||
|
|
@ -316,7 +357,7 @@ public class FaultHandlingDocSample {
|
|||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
// #messages
|
||||
public interface CounterApi {
|
||||
public static class UseStorage {
|
||||
public final ActorRef storage;
|
||||
|
|
@ -331,11 +372,11 @@ public class FaultHandlingDocSample {
|
|||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
// #messages
|
||||
|
||||
/**
|
||||
* The in memory count variable that will send current value to the Storage,
|
||||
* if there is any storage available at the moment.
|
||||
* The in memory count variable that will send current value to the Storage, if there is any
|
||||
* storage available at the moment.
|
||||
*/
|
||||
public static class Counter extends AbstractLoggingActor {
|
||||
final String key;
|
||||
|
|
@ -349,18 +390,27 @@ public class FaultHandlingDocSample {
|
|||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return LoggingReceive.create(receiveBuilder().
|
||||
match(UseStorage.class, useStorage -> {
|
||||
storage = useStorage.storage;
|
||||
storeCount();
|
||||
}).
|
||||
match(Increment.class, increment -> {
|
||||
count += increment.n;
|
||||
storeCount();
|
||||
}).
|
||||
matchEquals(GetCurrentCount, gcc -> {
|
||||
getSender().tell(new CurrentCount(key, count), getSelf());
|
||||
}).build(), getContext());
|
||||
return LoggingReceive.create(
|
||||
receiveBuilder()
|
||||
.match(
|
||||
UseStorage.class,
|
||||
useStorage -> {
|
||||
storage = useStorage.storage;
|
||||
storeCount();
|
||||
})
|
||||
.match(
|
||||
Increment.class,
|
||||
increment -> {
|
||||
count += increment.n;
|
||||
storeCount();
|
||||
})
|
||||
.matchEquals(
|
||||
GetCurrentCount,
|
||||
gcc -> {
|
||||
getSender().tell(new CurrentCount(key, count), getSelf());
|
||||
})
|
||||
.build(),
|
||||
getContext());
|
||||
}
|
||||
|
||||
void storeCount() {
|
||||
|
|
@ -372,7 +422,7 @@ public class FaultHandlingDocSample {
|
|||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
// #messages
|
||||
public interface StorageApi {
|
||||
|
||||
public static class Store {
|
||||
|
|
@ -415,18 +465,19 @@ public class FaultHandlingDocSample {
|
|||
|
||||
public static class StorageException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public StorageException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
// #messages
|
||||
|
||||
/**
|
||||
* Saves key/value pairs to persistent storage when receiving Store message.
|
||||
* Replies with current value when receiving Get message. Will throw
|
||||
* StorageException if the underlying data store is out of order.
|
||||
* Saves key/value pairs to persistent storage when receiving Store message. Replies with current
|
||||
* value when receiving Get message. Will throw StorageException if the underlying data store is
|
||||
* out of order.
|
||||
*/
|
||||
public static class Storage extends AbstractLoggingActor {
|
||||
|
||||
|
|
@ -434,25 +485,33 @@ public class FaultHandlingDocSample {
|
|||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return LoggingReceive.create(receiveBuilder().
|
||||
match(Store.class, store -> {
|
||||
db.save(store.entry.key, store.entry.value);
|
||||
}).
|
||||
match(Get.class, get -> {
|
||||
Long value = db.load(get.key);
|
||||
getSender().tell(new Entry(get.key, value == null ?
|
||||
Long.valueOf(0L) : value), getSelf());
|
||||
}).build(), getContext());
|
||||
return LoggingReceive.create(
|
||||
receiveBuilder()
|
||||
.match(
|
||||
Store.class,
|
||||
store -> {
|
||||
db.save(store.entry.key, store.entry.value);
|
||||
})
|
||||
.match(
|
||||
Get.class,
|
||||
get -> {
|
||||
Long value = db.load(get.key);
|
||||
getSender()
|
||||
.tell(
|
||||
new Entry(get.key, value == null ? Long.valueOf(0L) : value),
|
||||
getSelf());
|
||||
})
|
||||
.build(),
|
||||
getContext());
|
||||
}
|
||||
}
|
||||
|
||||
//#dummydb
|
||||
// #dummydb
|
||||
public static class DummyDB {
|
||||
public static final DummyDB instance = new DummyDB();
|
||||
private final Map<String, Long> db = new HashMap<String, Long>();
|
||||
|
||||
private DummyDB() {
|
||||
}
|
||||
private DummyDB() {}
|
||||
|
||||
public synchronized void save(String key, Long value) throws StorageException {
|
||||
if (11 <= value && value <= 14)
|
||||
|
|
@ -464,6 +523,6 @@ public class FaultHandlingDocSample {
|
|||
return db.get(key);
|
||||
}
|
||||
}
|
||||
//#dummydb
|
||||
// #dummydb
|
||||
}
|
||||
//#all
|
||||
// #all
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ package jdocs.actor;
|
|||
|
||||
import akka.actor.*;
|
||||
|
||||
|
||||
import akka.testkit.javadsl.TestKit;
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
|
|
@ -16,7 +15,7 @@ import java.time.Duration;
|
|||
|
||||
import static akka.pattern.Patterns.ask;
|
||||
|
||||
//#testkit
|
||||
// #testkit
|
||||
import akka.testkit.TestProbe;
|
||||
import akka.testkit.ErrorFilter;
|
||||
import akka.testkit.EventFilter;
|
||||
|
|
@ -25,89 +24,97 @@ import static java.util.concurrent.TimeUnit.SECONDS;
|
|||
import static akka.japi.Util.immutableSeq;
|
||||
import scala.concurrent.Await;
|
||||
|
||||
//#testkit
|
||||
// #testkit
|
||||
|
||||
//#supervisor
|
||||
// #supervisor
|
||||
import akka.japi.pf.DeciderBuilder;
|
||||
import akka.actor.SupervisorStrategy;
|
||||
|
||||
//#supervisor
|
||||
// #supervisor
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.AfterClass;
|
||||
|
||||
//#testkit
|
||||
// #testkit
|
||||
public class FaultHandlingTest extends AbstractJavaTest {
|
||||
//#testkit
|
||||
// #testkit
|
||||
|
||||
public static Config config = ConfigFactory.parseString(
|
||||
"akka {\n" +
|
||||
" loggers = [\"akka.testkit.TestEventListener\"]\n" +
|
||||
" loglevel = \"WARNING\"\n" +
|
||||
" stdout-loglevel = \"WARNING\"\n" +
|
||||
"}\n");
|
||||
public static Config config =
|
||||
ConfigFactory.parseString(
|
||||
"akka {\n"
|
||||
+ " loggers = [\"akka.testkit.TestEventListener\"]\n"
|
||||
+ " loglevel = \"WARNING\"\n"
|
||||
+ " stdout-loglevel = \"WARNING\"\n"
|
||||
+ "}\n");
|
||||
|
||||
static
|
||||
//#supervisor
|
||||
public class Supervisor extends AbstractActor {
|
||||
public
|
||||
// #supervisor
|
||||
static class Supervisor extends AbstractActor {
|
||||
|
||||
//#strategy
|
||||
// #strategy
|
||||
private static SupervisorStrategy strategy =
|
||||
new OneForOneStrategy(10, Duration.ofMinutes(1),
|
||||
DeciderBuilder
|
||||
.match(ArithmeticException.class, e -> SupervisorStrategy.resume())
|
||||
.match(NullPointerException.class, e -> SupervisorStrategy.restart())
|
||||
.match(IllegalArgumentException.class, e -> SupervisorStrategy.stop())
|
||||
.matchAny(o -> SupervisorStrategy.escalate())
|
||||
.build());
|
||||
new OneForOneStrategy(
|
||||
10,
|
||||
Duration.ofMinutes(1),
|
||||
DeciderBuilder.match(ArithmeticException.class, e -> SupervisorStrategy.resume())
|
||||
.match(NullPointerException.class, e -> SupervisorStrategy.restart())
|
||||
.match(IllegalArgumentException.class, e -> SupervisorStrategy.stop())
|
||||
.matchAny(o -> SupervisorStrategy.escalate())
|
||||
.build());
|
||||
|
||||
@Override
|
||||
public SupervisorStrategy supervisorStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
//#strategy
|
||||
// #strategy
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Props.class, props -> {
|
||||
getSender().tell(getContext().actorOf(props), getSelf());
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
Props.class,
|
||||
props -> {
|
||||
getSender().tell(getContext().actorOf(props), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
//#supervisor
|
||||
// #supervisor
|
||||
|
||||
static
|
||||
//#supervisor2
|
||||
public class Supervisor2 extends AbstractActor {
|
||||
public
|
||||
// #supervisor2
|
||||
static class Supervisor2 extends AbstractActor {
|
||||
|
||||
//#strategy2
|
||||
// #strategy2
|
||||
private static SupervisorStrategy strategy =
|
||||
new OneForOneStrategy(10, Duration.ofMinutes(1), DeciderBuilder.
|
||||
match(ArithmeticException.class, e -> SupervisorStrategy.resume()).
|
||||
match(NullPointerException.class, e -> SupervisorStrategy.restart()).
|
||||
match(IllegalArgumentException.class, e -> SupervisorStrategy.stop()).
|
||||
matchAny(o -> SupervisorStrategy.escalate())
|
||||
.build());
|
||||
new OneForOneStrategy(
|
||||
10,
|
||||
Duration.ofMinutes(1),
|
||||
DeciderBuilder.match(ArithmeticException.class, e -> SupervisorStrategy.resume())
|
||||
.match(NullPointerException.class, e -> SupervisorStrategy.restart())
|
||||
.match(IllegalArgumentException.class, e -> SupervisorStrategy.stop())
|
||||
.matchAny(o -> SupervisorStrategy.escalate())
|
||||
.build());
|
||||
|
||||
@Override
|
||||
public SupervisorStrategy supervisorStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
//#strategy2
|
||||
// #strategy2
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Props.class, props -> {
|
||||
getSender().tell(getContext().actorOf(props), getSelf());
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
Props.class,
|
||||
props -> {
|
||||
getSender().tell(getContext().actorOf(props), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -116,28 +123,33 @@ public class FaultHandlingTest extends AbstractJavaTest {
|
|||
}
|
||||
}
|
||||
|
||||
//#supervisor2
|
||||
// #supervisor2
|
||||
|
||||
static
|
||||
//#child
|
||||
public class Child extends AbstractActor {
|
||||
public
|
||||
// #child
|
||||
static class Child extends AbstractActor {
|
||||
int state = 0;
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Exception.class, exception -> { throw exception; })
|
||||
.match(Integer.class, i -> state = i)
|
||||
.matchEquals("get", s -> getSender().tell(state, getSelf()))
|
||||
.build();
|
||||
.match(
|
||||
Exception.class,
|
||||
exception -> {
|
||||
throw exception;
|
||||
})
|
||||
.match(Integer.class, i -> state = i)
|
||||
.matchEquals("get", s -> getSender().tell(state, getSelf()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
//#child
|
||||
// #child
|
||||
|
||||
//#testkit
|
||||
// #testkit
|
||||
static ActorSystem system;
|
||||
scala.concurrent.duration.Duration timeout = scala.concurrent.duration.Duration.create(5, SECONDS);
|
||||
scala.concurrent.duration.Duration timeout =
|
||||
scala.concurrent.duration.Duration.create(5, SECONDS);
|
||||
|
||||
@BeforeClass
|
||||
public static void start() {
|
||||
|
|
@ -153,61 +165,58 @@ public class FaultHandlingTest extends AbstractJavaTest {
|
|||
@Test
|
||||
public void mustEmploySupervisorStrategy() throws Exception {
|
||||
// code here
|
||||
//#testkit
|
||||
// #testkit
|
||||
EventFilter ex1 = new ErrorFilter(ArithmeticException.class);
|
||||
EventFilter ex2 = new ErrorFilter(NullPointerException.class);
|
||||
EventFilter ex3 = new ErrorFilter(IllegalArgumentException.class);
|
||||
EventFilter ex4 = new ErrorFilter(Exception.class);
|
||||
EventFilter[] ignoreExceptions = { ex1, ex2, ex3, ex4 };
|
||||
EventFilter[] ignoreExceptions = {ex1, ex2, ex3, ex4};
|
||||
system.getEventStream().publish(new TestEvent.Mute(immutableSeq(ignoreExceptions)));
|
||||
|
||||
//#create
|
||||
// #create
|
||||
Props superprops = Props.create(Supervisor.class);
|
||||
ActorRef supervisor = system.actorOf(superprops, "supervisor");
|
||||
ActorRef child = (ActorRef) Await.result(ask(supervisor,
|
||||
Props.create(Child.class), 5000), timeout);
|
||||
//#create
|
||||
ActorRef child =
|
||||
(ActorRef) Await.result(ask(supervisor, Props.create(Child.class), 5000), timeout);
|
||||
// #create
|
||||
|
||||
//#resume
|
||||
// #resume
|
||||
child.tell(42, ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(42);
|
||||
child.tell(new ArithmeticException(), ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(42);
|
||||
//#resume
|
||||
// #resume
|
||||
|
||||
//#restart
|
||||
// #restart
|
||||
child.tell(new NullPointerException(), ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(0);
|
||||
//#restart
|
||||
// #restart
|
||||
|
||||
//#stop
|
||||
// #stop
|
||||
final TestProbe probe = new TestProbe(system);
|
||||
probe.watch(child);
|
||||
child.tell(new IllegalArgumentException(), ActorRef.noSender());
|
||||
probe.expectMsgClass(Terminated.class);
|
||||
//#stop
|
||||
// #stop
|
||||
|
||||
//#escalate-kill
|
||||
child = (ActorRef) Await.result(ask(supervisor,
|
||||
Props.create(Child.class), 5000), timeout);
|
||||
// #escalate-kill
|
||||
child = (ActorRef) Await.result(ask(supervisor, Props.create(Child.class), 5000), timeout);
|
||||
probe.watch(child);
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(0);
|
||||
child.tell(new Exception(), ActorRef.noSender());
|
||||
probe.expectMsgClass(Terminated.class);
|
||||
//#escalate-kill
|
||||
// #escalate-kill
|
||||
|
||||
//#escalate-restart
|
||||
// #escalate-restart
|
||||
superprops = Props.create(Supervisor2.class);
|
||||
supervisor = system.actorOf(superprops);
|
||||
child = (ActorRef) Await.result(ask(supervisor,
|
||||
Props.create(Child.class), 5000), timeout);
|
||||
child = (ActorRef) Await.result(ask(supervisor, Props.create(Child.class), 5000), timeout);
|
||||
child.tell(23, ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(23);
|
||||
child.tell(new Exception(), ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(0);
|
||||
//#escalate-restart
|
||||
//#testkit
|
||||
// #escalate-restart
|
||||
// #testkit
|
||||
}
|
||||
|
||||
}
|
||||
//#testkit
|
||||
// #testkit
|
||||
|
|
|
|||
|
|
@ -4,36 +4,38 @@
|
|||
|
||||
package jdocs.actor;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
|
||||
//#actor
|
||||
// #actor
|
||||
public class GraduallyBuiltActor extends AbstractActor {
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
ReceiveBuilder builder = ReceiveBuilder.create();
|
||||
|
||||
builder.match(String.class, s -> {
|
||||
log.info("Received String message: {}", s);
|
||||
//#actor
|
||||
//#reply
|
||||
getSender().tell(s, getSelf());
|
||||
//#reply
|
||||
//#actor
|
||||
});
|
||||
|
||||
|
||||
builder.match(
|
||||
String.class,
|
||||
s -> {
|
||||
log.info("Received String message: {}", s);
|
||||
// #actor
|
||||
// #reply
|
||||
getSender().tell(s, getSelf());
|
||||
// #reply
|
||||
// #actor
|
||||
});
|
||||
|
||||
// do some other stuff in between
|
||||
|
||||
|
||||
builder.matchAny(o -> log.info("received unknown message"));
|
||||
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
//#actor
|
||||
// #actor
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
//#immutable-message
|
||||
// #immutable-message
|
||||
public class ImmutableMessage {
|
||||
private final int sequenceNumber;
|
||||
private final List<String> values;
|
||||
|
|
@ -26,4 +26,4 @@ public class ImmutableMessage {
|
|||
return values;
|
||||
}
|
||||
}
|
||||
//#immutable-message
|
||||
// #immutable-message
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ public class InboxDocTest extends AbstractJavaTest {
|
|||
|
||||
@ClassRule
|
||||
public static AkkaJUnitActorSystemResource actorSystemResource =
|
||||
new AkkaJUnitActorSystemResource("InboxDocTest", AkkaSpec.testConf());
|
||||
new AkkaJUnitActorSystemResource("InboxDocTest", AkkaSpec.testConf());
|
||||
|
||||
private final ActorSystem system = actorSystemResource.getSystem();
|
||||
|
||||
|
|
@ -31,26 +31,26 @@ public class InboxDocTest extends AbstractJavaTest {
|
|||
public void demonstrateInbox() {
|
||||
final TestKit probe = new TestKit(system);
|
||||
final ActorRef target = probe.getRef();
|
||||
//#inbox
|
||||
// #inbox
|
||||
final Inbox inbox = Inbox.create(system);
|
||||
inbox.send(target, "hello");
|
||||
//#inbox
|
||||
// #inbox
|
||||
probe.expectMsgEquals("hello");
|
||||
probe.send(probe.getLastSender(), "world");
|
||||
//#inbox
|
||||
// #inbox
|
||||
try {
|
||||
assert inbox.receive(Duration.ofSeconds(1)).equals("world");
|
||||
} catch (java.util.concurrent.TimeoutException e) {
|
||||
// timeout
|
||||
}
|
||||
//#inbox
|
||||
// #inbox
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateWatch() {
|
||||
final TestKit probe = new TestKit(system);
|
||||
final ActorRef target = probe.getRef();
|
||||
//#watch
|
||||
// #watch
|
||||
final Inbox inbox = Inbox.create(system);
|
||||
inbox.watch(target);
|
||||
target.tell(PoisonPill.getInstance(), ActorRef.noSender());
|
||||
|
|
@ -59,7 +59,6 @@ public class InboxDocTest extends AbstractJavaTest {
|
|||
} catch (java.util.concurrent.TimeoutException e) {
|
||||
// timeout
|
||||
}
|
||||
//#watch
|
||||
// #watch
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,15 +31,15 @@ public class InitializationDocTest extends AbstractJavaTest {
|
|||
public static void afterClass() {
|
||||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
||||
static public class PreStartInitExample extends AbstractActor {
|
||||
|
||||
public static class PreStartInitExample extends AbstractActor {
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return AbstractActor.emptyBehavior();
|
||||
}
|
||||
|
||||
//#preStartInit
|
||||
// #preStartInit
|
||||
@Override
|
||||
public void preStart() {
|
||||
// Initialize children here
|
||||
|
|
@ -48,40 +48,44 @@ public class InitializationDocTest extends AbstractJavaTest {
|
|||
// Overriding postRestart to disable the call to preStart()
|
||||
// after restarts
|
||||
@Override
|
||||
public void postRestart(Throwable reason) {
|
||||
}
|
||||
public void postRestart(Throwable reason) {}
|
||||
|
||||
// The default implementation of preRestart() stops all the children
|
||||
// of the actor. To opt-out from stopping the children, we
|
||||
// have to override preRestart()
|
||||
@Override
|
||||
public void preRestart(Throwable reason, Optional<Object> message)
|
||||
throws Exception {
|
||||
public void preRestart(Throwable reason, Optional<Object> message) throws Exception {
|
||||
// Keep the call to postStop(), but no stopping of children
|
||||
postStop();
|
||||
}
|
||||
//#preStartInit
|
||||
// #preStartInit
|
||||
|
||||
}
|
||||
|
||||
public static class MessageInitExample extends AbstractActor {
|
||||
private String initializeMe = null;
|
||||
|
||||
//#messageInit
|
||||
// #messageInit
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("init", m1 -> {
|
||||
initializeMe = "Up and running";
|
||||
getContext().become(receiveBuilder()
|
||||
.matchEquals("U OK?", m2 -> {
|
||||
getSender().tell(initializeMe, getSelf());
|
||||
})
|
||||
.build());
|
||||
})
|
||||
.build();
|
||||
.matchEquals(
|
||||
"init",
|
||||
m1 -> {
|
||||
initializeMe = "Up and running";
|
||||
getContext()
|
||||
.become(
|
||||
receiveBuilder()
|
||||
.matchEquals(
|
||||
"U OK?",
|
||||
m2 -> {
|
||||
getSender().tell(initializeMe, getSelf());
|
||||
})
|
||||
.build());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
//#messageInit
|
||||
// #messageInit
|
||||
}
|
||||
|
||||
public class GenericMessage<T> {
|
||||
|
|
@ -96,11 +100,13 @@ public class InitializationDocTest extends AbstractJavaTest {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchUnchecked(GenericMessage.class, (GenericMessage<String> msg) -> {
|
||||
GenericMessage<String> message = msg;
|
||||
getSender().tell(message.value.toUpperCase(), getSelf());
|
||||
})
|
||||
.build();
|
||||
.matchUnchecked(
|
||||
GenericMessage.class,
|
||||
(GenericMessage<String> msg) -> {
|
||||
GenericMessage<String> message = msg;
|
||||
getSender().tell(message.value.toUpperCase(), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,82 +116,102 @@ public class InitializationDocTest extends AbstractJavaTest {
|
|||
FI.TypedPredicate<GenericMessage<String>> typedPredicate = s -> !s.value.isEmpty();
|
||||
|
||||
return receiveBuilder()
|
||||
.matchUnchecked(GenericMessage.class, typedPredicate, (GenericMessage<String> msg) -> {
|
||||
getSender().tell(msg.value.toUpperCase(), getSelf());
|
||||
})
|
||||
.build();
|
||||
.matchUnchecked(
|
||||
GenericMessage.class,
|
||||
typedPredicate,
|
||||
(GenericMessage<String> msg) -> {
|
||||
getSender().tell(msg.value.toUpperCase(), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
static class GenericActorWithPredicateAlwaysResponse extends AbstractActor {
|
||||
private boolean alwaysResponse() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchUnchecked(GenericMessage.class, this::alwaysResponse, (GenericMessage<String> msg) -> {
|
||||
getSender().tell(msg.value.toUpperCase(), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
private boolean alwaysResponse() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchUnchecked(
|
||||
GenericMessage.class,
|
||||
this::alwaysResponse,
|
||||
(GenericMessage<String> msg) -> {
|
||||
getSender().tell(msg.value.toUpperCase(), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIt() {
|
||||
|
||||
new TestKit(system) {{
|
||||
ActorRef testactor = system.actorOf(Props.create(MessageInitExample.class), "testactor");
|
||||
String msg = "U OK?";
|
||||
new TestKit(system) {
|
||||
{
|
||||
ActorRef testactor = system.actorOf(Props.create(MessageInitExample.class), "testactor");
|
||||
String msg = "U OK?";
|
||||
|
||||
testactor.tell(msg, getRef());
|
||||
expectNoMessage(Duration.ofSeconds(1));
|
||||
testactor.tell(msg, getRef());
|
||||
expectNoMessage(Duration.ofSeconds(1));
|
||||
|
||||
testactor.tell("init", getRef());
|
||||
testactor.tell(msg, getRef());
|
||||
expectMsgEquals("Up and running");
|
||||
}};
|
||||
testactor.tell("init", getRef());
|
||||
testactor.tell(msg, getRef());
|
||||
expectMsgEquals("Up and running");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenericActor() {
|
||||
new TestKit(system) {{
|
||||
ActorRef genericTestActor = system.actorOf(Props.create(GenericActor.class), "genericActor");
|
||||
GenericMessage<String> genericMessage = new GenericMessage<String>("a");
|
||||
new TestKit(system) {
|
||||
{
|
||||
ActorRef genericTestActor =
|
||||
system.actorOf(Props.create(GenericActor.class), "genericActor");
|
||||
GenericMessage<String> genericMessage = new GenericMessage<String>("a");
|
||||
|
||||
genericTestActor.tell(genericMessage, getRef());
|
||||
expectMsgEquals("A");
|
||||
}};
|
||||
genericTestActor.tell(genericMessage, getRef());
|
||||
expectMsgEquals("A");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void actorShouldNotRespondForEmptyMessage() {
|
||||
new TestKit(system) {{
|
||||
ActorRef genericTestActor = system.actorOf(Props.create(GenericActorWithPredicate.class), "genericActorWithPredicate");
|
||||
GenericMessage<String> emptyGenericMessage = new GenericMessage<String>("");
|
||||
GenericMessage<String> nonEmptyGenericMessage = new GenericMessage<String>("a");
|
||||
new TestKit(system) {
|
||||
{
|
||||
ActorRef genericTestActor =
|
||||
system.actorOf(
|
||||
Props.create(GenericActorWithPredicate.class), "genericActorWithPredicate");
|
||||
GenericMessage<String> emptyGenericMessage = new GenericMessage<String>("");
|
||||
GenericMessage<String> nonEmptyGenericMessage = new GenericMessage<String>("a");
|
||||
|
||||
genericTestActor.tell(emptyGenericMessage, getRef());
|
||||
expectNoMessage();
|
||||
genericTestActor.tell(emptyGenericMessage, getRef());
|
||||
expectNoMessage();
|
||||
|
||||
genericTestActor.tell(nonEmptyGenericMessage, getRef());
|
||||
expectMsgEquals("A");
|
||||
}};
|
||||
genericTestActor.tell(nonEmptyGenericMessage, getRef());
|
||||
expectMsgEquals("A");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void actorShouldAlwaysRespondForEmptyMessage() {
|
||||
new TestKit(system) {{
|
||||
ActorRef genericTestActor = system.actorOf(Props.create(GenericActorWithPredicateAlwaysResponse.class), "genericActorWithPredicateAlwaysResponse");
|
||||
GenericMessage<String> emptyGenericMessage = new GenericMessage<String>("");
|
||||
GenericMessage<String> nonEmptyGenericMessage = new GenericMessage<String>("a");
|
||||
@Test
|
||||
public void actorShouldAlwaysRespondForEmptyMessage() {
|
||||
new TestKit(system) {
|
||||
{
|
||||
ActorRef genericTestActor =
|
||||
system.actorOf(
|
||||
Props.create(GenericActorWithPredicateAlwaysResponse.class),
|
||||
"genericActorWithPredicateAlwaysResponse");
|
||||
GenericMessage<String> emptyGenericMessage = new GenericMessage<String>("");
|
||||
GenericMessage<String> nonEmptyGenericMessage = new GenericMessage<String>("a");
|
||||
|
||||
genericTestActor.tell(emptyGenericMessage, getRef());
|
||||
expectMsg("");
|
||||
genericTestActor.tell(emptyGenericMessage, getRef());
|
||||
expectMsg("");
|
||||
|
||||
genericTestActor.tell(nonEmptyGenericMessage, getRef());
|
||||
expectMsgEquals("A");
|
||||
}};
|
||||
}
|
||||
genericTestActor.tell(nonEmptyGenericMessage, getRef());
|
||||
expectMsgEquals("A");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
|
||||
public class Messages {
|
||||
static
|
||||
//#immutable-message
|
||||
public class ImmutableMessage {
|
||||
public
|
||||
// #immutable-message
|
||||
static class ImmutableMessage {
|
||||
private final int sequenceNumber;
|
||||
private final List<String> values;
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ public class Messages {
|
|||
return values;
|
||||
}
|
||||
}
|
||||
//#immutable-message
|
||||
// #immutable-message
|
||||
|
||||
public static class DoIt {
|
||||
private final ImmutableMessage msg;
|
||||
|
|
@ -60,9 +60,7 @@ public class Messages {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DoIt{" +
|
||||
"msg=" + msg +
|
||||
'}';
|
||||
return "DoIt{" + "msg=" + msg + '}';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,9 +94,7 @@ public class Messages {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Message{" +
|
||||
"str='" + str + '\'' +
|
||||
'}';
|
||||
return "Message{" + "str='" + str + '\'' + '}';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -126,23 +122,16 @@ public class Messages {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
Result other = (Result) obj;
|
||||
if (s == null) {
|
||||
if (other.s != null)
|
||||
return false;
|
||||
} else if (!s.equals(other.s))
|
||||
return false;
|
||||
if (other.s != null) return false;
|
||||
} else if (!s.equals(other.s)) return false;
|
||||
if (x == null) {
|
||||
if (other.x != null)
|
||||
return false;
|
||||
} else if (!x.equals(other.x))
|
||||
return false;
|
||||
if (other.x != null) return false;
|
||||
} else if (!x.equals(other.x)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,30 +4,32 @@
|
|||
|
||||
package jdocs.actor;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
|
||||
//#my-actor
|
||||
// #my-actor
|
||||
public class MyActor extends AbstractActor {
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(String.class, s -> {
|
||||
log.info("Received String message: {}", s);
|
||||
//#my-actor
|
||||
//#reply
|
||||
getSender().tell(s, getSelf());
|
||||
//#reply
|
||||
//#my-actor
|
||||
})
|
||||
.matchAny(o -> log.info("received unknown message"))
|
||||
.build();
|
||||
.match(
|
||||
String.class,
|
||||
s -> {
|
||||
log.info("Received String message: {}", s);
|
||||
// #my-actor
|
||||
// #reply
|
||||
getSender().tell(s, getSelf());
|
||||
// #reply
|
||||
// #my-actor
|
||||
})
|
||||
.matchAny(o -> log.info("received unknown message"))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#my-actor
|
||||
// #my-actor
|
||||
|
|
|
|||
|
|
@ -4,11 +4,10 @@
|
|||
|
||||
package jdocs.actor;
|
||||
|
||||
//#my-bounded-untyped-actor
|
||||
// #my-bounded-untyped-actor
|
||||
import akka.dispatch.BoundedMessageQueueSemantics;
|
||||
import akka.dispatch.RequiresMessageQueue;
|
||||
|
||||
public class MyBoundedActor extends MyActor
|
||||
implements RequiresMessageQueue<BoundedMessageQueueSemantics> {
|
||||
}
|
||||
//#my-bounded-untyped-actor
|
||||
implements RequiresMessageQueue<BoundedMessageQueueSemantics> {}
|
||||
// #my-bounded-untyped-actor
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package jdocs.actor;
|
||||
|
||||
//#my-stopping-actor
|
||||
// #my-stopping-actor
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.AbstractActor;
|
||||
|
||||
|
|
@ -17,14 +17,9 @@ public class MyStoppingActor extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("interrupt-child", m ->
|
||||
getContext().stop(child)
|
||||
)
|
||||
.matchEquals("done", m ->
|
||||
getContext().stop(getSelf())
|
||||
)
|
||||
.build();
|
||||
.matchEquals("interrupt-child", m -> getContext().stop(child))
|
||||
.matchEquals("done", m -> getContext().stop(getSelf()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#my-stopping-actor
|
||||
|
||||
// #my-stopping-actor
|
||||
|
|
|
|||
|
|
@ -11,10 +11,12 @@ class PrintActor extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Integer.class, i -> {
|
||||
System.out.println("PrintActor: " + i);
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
Integer.class,
|
||||
i -> {
|
||||
System.out.println("PrintActor: " + i);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
// #print-actor
|
||||
|
|
|
|||
|
|
@ -4,32 +4,43 @@
|
|||
|
||||
package jdocs.actor;
|
||||
|
||||
//#sample-actor
|
||||
// #sample-actor
|
||||
import akka.actor.AbstractActor;
|
||||
|
||||
public class SampleActor extends AbstractActor {
|
||||
|
||||
private Receive guarded = receiveBuilder()
|
||||
.match(String.class, s -> s.contains("guard"), s -> {
|
||||
getSender().tell("contains(guard): " + s, getSelf());
|
||||
getContext().unbecome();
|
||||
})
|
||||
.build();
|
||||
private Receive guarded =
|
||||
receiveBuilder()
|
||||
.match(
|
||||
String.class,
|
||||
s -> s.contains("guard"),
|
||||
s -> {
|
||||
getSender().tell("contains(guard): " + s, getSelf());
|
||||
getContext().unbecome();
|
||||
})
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Double.class, d -> {
|
||||
getSender().tell(d.isNaN() ? 0 : d, getSelf());
|
||||
})
|
||||
.match(Integer.class, i -> {
|
||||
getSender().tell(i * 10, getSelf());
|
||||
})
|
||||
.match(String.class, s -> s.startsWith("guard"), s -> {
|
||||
getSender().tell("startsWith(guard): " + s.toUpperCase(), getSelf());
|
||||
getContext().become(guarded, false);
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
Double.class,
|
||||
d -> {
|
||||
getSender().tell(d.isNaN() ? 0 : d, getSelf());
|
||||
})
|
||||
.match(
|
||||
Integer.class,
|
||||
i -> {
|
||||
getSender().tell(i * 10, getSelf());
|
||||
})
|
||||
.match(
|
||||
String.class,
|
||||
s -> s.startsWith("guard"),
|
||||
s -> {
|
||||
getSender().tell("startsWith(guard): " + s.toUpperCase(), getSelf());
|
||||
getContext().become(guarded, false);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#sample-actor
|
||||
// #sample-actor
|
||||
|
|
|
|||
|
|
@ -31,26 +31,27 @@ public class SampleActorTest extends AbstractJavaTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSampleActor()
|
||||
{
|
||||
new TestKit(system) {{
|
||||
final ActorRef subject = system.actorOf(Props.create(SampleActor.class), "sample-actor");
|
||||
final ActorRef probeRef = getRef();
|
||||
public void testSampleActor() {
|
||||
new TestKit(system) {
|
||||
{
|
||||
final ActorRef subject = system.actorOf(Props.create(SampleActor.class), "sample-actor");
|
||||
final ActorRef probeRef = getRef();
|
||||
|
||||
subject.tell(47.11, probeRef);
|
||||
subject.tell("and no guard in the beginning", probeRef);
|
||||
subject.tell("guard is a good thing", probeRef);
|
||||
subject.tell(47.11, probeRef);
|
||||
subject.tell(4711, probeRef);
|
||||
subject.tell("and no guard in the beginning", probeRef);
|
||||
subject.tell(4711, probeRef);
|
||||
subject.tell("and an unmatched message", probeRef);
|
||||
subject.tell(47.11, probeRef);
|
||||
subject.tell("and no guard in the beginning", probeRef);
|
||||
subject.tell("guard is a good thing", probeRef);
|
||||
subject.tell(47.11, probeRef);
|
||||
subject.tell(4711, probeRef);
|
||||
subject.tell("and no guard in the beginning", probeRef);
|
||||
subject.tell(4711, probeRef);
|
||||
subject.tell("and an unmatched message", probeRef);
|
||||
|
||||
expectMsgEquals(47.11);
|
||||
assertTrue(expectMsgClass(String.class).startsWith("startsWith(guard):"));
|
||||
assertTrue(expectMsgClass(String.class).startsWith("contains(guard):"));
|
||||
expectMsgEquals(47110);
|
||||
expectNoMessage();
|
||||
}};
|
||||
expectMsgEquals(47.11);
|
||||
assertTrue(expectMsgClass(String.class).startsWith("startsWith(guard):"));
|
||||
assertTrue(expectMsgClass(String.class).startsWith("contains(guard):"));
|
||||
expectMsgEquals(47110);
|
||||
expectNoMessage();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@
|
|||
|
||||
package jdocs.actor;
|
||||
|
||||
//#imports1
|
||||
// #imports1
|
||||
import akka.actor.Props;
|
||||
import jdocs.AbstractJavaTest;
|
||||
import java.time.Duration;
|
||||
//#imports1
|
||||
// #imports1
|
||||
|
||||
//#imports2
|
||||
// #imports2
|
||||
import akka.actor.Cancellable;
|
||||
//#imports2
|
||||
// #imports2
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.ActorRef;
|
||||
|
|
@ -22,57 +22,66 @@ import akka.testkit.AkkaJUnitActorSystemResource;
|
|||
import org.junit.*;
|
||||
|
||||
public class SchedulerDocTest extends AbstractJavaTest {
|
||||
|
||||
|
||||
@ClassRule
|
||||
public static AkkaJUnitActorSystemResource actorSystemResource = new AkkaJUnitActorSystemResource("SchedulerDocTest",
|
||||
AkkaSpec.testConf());
|
||||
public static AkkaJUnitActorSystemResource actorSystemResource =
|
||||
new AkkaJUnitActorSystemResource("SchedulerDocTest", AkkaSpec.testConf());
|
||||
|
||||
private final ActorSystem system = actorSystemResource.getSystem();
|
||||
private ActorRef testActor = system.actorOf(Props.create(MyActor.class));
|
||||
|
||||
@Test
|
||||
public void scheduleOneOffTask() {
|
||||
//#schedule-one-off-message
|
||||
system.scheduler().scheduleOnce(Duration.ofMillis(50),
|
||||
testActor, "foo", system.dispatcher(), null);
|
||||
//#schedule-one-off-message
|
||||
// #schedule-one-off-message
|
||||
system
|
||||
.scheduler()
|
||||
.scheduleOnce(Duration.ofMillis(50), testActor, "foo", system.dispatcher(), null);
|
||||
// #schedule-one-off-message
|
||||
|
||||
//#schedule-one-off-thunk
|
||||
system.scheduler().scheduleOnce(Duration.ofMillis(50),
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
testActor.tell(System.currentTimeMillis(), ActorRef.noSender());
|
||||
}
|
||||
}, system.dispatcher());
|
||||
//#schedule-one-off-thunk
|
||||
// #schedule-one-off-thunk
|
||||
system
|
||||
.scheduler()
|
||||
.scheduleOnce(
|
||||
Duration.ofMillis(50),
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
testActor.tell(System.currentTimeMillis(), ActorRef.noSender());
|
||||
}
|
||||
},
|
||||
system.dispatcher());
|
||||
// #schedule-one-off-thunk
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scheduleRecurringTask() {
|
||||
//#schedule-recurring
|
||||
// #schedule-recurring
|
||||
class Ticker extends AbstractActor {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("Tick", m -> {
|
||||
// Do someting
|
||||
})
|
||||
.build();
|
||||
.matchEquals(
|
||||
"Tick",
|
||||
m -> {
|
||||
// Do someting
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ActorRef tickActor = system.actorOf(Props.create(Ticker.class, this));
|
||||
|
||||
//This will schedule to send the Tick-message
|
||||
//to the tickActor after 0ms repeating every 50ms
|
||||
Cancellable cancellable = system.scheduler().schedule(Duration.ZERO,
|
||||
Duration.ofMillis(50), tickActor, "Tick",
|
||||
system.dispatcher(), null);
|
||||
// This will schedule to send the Tick-message
|
||||
// to the tickActor after 0ms repeating every 50ms
|
||||
Cancellable cancellable =
|
||||
system
|
||||
.scheduler()
|
||||
.schedule(
|
||||
Duration.ZERO, Duration.ofMillis(50), tickActor, "Tick", system.dispatcher(), null);
|
||||
|
||||
//This cancels further Ticks to be sent
|
||||
// This cancels further Ticks to be sent
|
||||
cancellable.cancel();
|
||||
//#schedule-recurring
|
||||
// #schedule-recurring
|
||||
system.stop(tickActor);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,15 +16,20 @@ class SeparateDispatcherFutureActor extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Integer.class, i -> {
|
||||
System.out.println("Calling blocking Future on separate dispatcher: " + i);
|
||||
Future<Integer> f = Futures.future(() -> {
|
||||
Thread.sleep(5000);
|
||||
System.out.println("Blocking future finished: " + i);
|
||||
return i;
|
||||
}, ec);
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
Integer.class,
|
||||
i -> {
|
||||
System.out.println("Calling blocking Future on separate dispatcher: " + i);
|
||||
Future<Integer> f =
|
||||
Futures.future(
|
||||
() -> {
|
||||
Thread.sleep(5000);
|
||||
System.out.println("Blocking future finished: " + i);
|
||||
return i;
|
||||
},
|
||||
ec);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
// #separate-dispatcher
|
||||
// #separate-dispatcher
|
||||
|
|
|
|||
|
|
@ -12,16 +12,16 @@ import com.typesafe.config.ConfigFactory;
|
|||
|
||||
class SeparateDispatcherTest {
|
||||
public static void main(String args[]) {
|
||||
Config config = ConfigFactory.parseString(
|
||||
"my-blocking-dispatcher {\n" +
|
||||
" type = Dispatcher\n" +
|
||||
" executor = \"thread-pool-executor\"\n" +
|
||||
" thread-pool-executor {\n" +
|
||||
" fixed-pool-size = 16\n" +
|
||||
" }\n" +
|
||||
" throughput = 1\n" +
|
||||
"}\n"
|
||||
);
|
||||
Config config =
|
||||
ConfigFactory.parseString(
|
||||
"my-blocking-dispatcher {\n"
|
||||
+ " type = Dispatcher\n"
|
||||
+ " executor = \"thread-pool-executor\"\n"
|
||||
+ " thread-pool-executor {\n"
|
||||
+ " fixed-pool-size = 16\n"
|
||||
+ " }\n"
|
||||
+ " throughput = 1\n"
|
||||
+ "}\n");
|
||||
|
||||
ActorSystem system = ActorSystem.create("BlockingDispatcherTest", config);
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ class SeparateDispatcherTest {
|
|||
Thread.sleep(5000 * 6);
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
//swallow the exception
|
||||
// swallow the exception
|
||||
} finally {
|
||||
system.terminate();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,23 +4,23 @@
|
|||
|
||||
package jdocs.actor;
|
||||
|
||||
//#timers
|
||||
// #timers
|
||||
import java.time.Duration;
|
||||
import akka.actor.AbstractActorWithTimers;
|
||||
|
||||
//#timers
|
||||
// #timers
|
||||
|
||||
public class TimerDocTest {
|
||||
|
||||
static
|
||||
//#timers
|
||||
public class MyActor extends AbstractActorWithTimers {
|
||||
|
||||
public
|
||||
// #timers
|
||||
static class MyActor extends AbstractActorWithTimers {
|
||||
|
||||
private static Object TICK_KEY = "TickKey";
|
||||
private static final class FirstTick {
|
||||
}
|
||||
private static final class Tick {
|
||||
}
|
||||
|
||||
private static final class FirstTick {}
|
||||
|
||||
private static final class Tick {}
|
||||
|
||||
public MyActor() {
|
||||
getTimers().startSingleTimer(TICK_KEY, new FirstTick(), Duration.ofMillis(500));
|
||||
|
|
@ -29,15 +29,19 @@ public class TimerDocTest {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(FirstTick.class, message -> {
|
||||
// do something useful here
|
||||
getTimers().startPeriodicTimer(TICK_KEY, new Tick(), Duration.ofSeconds(1));
|
||||
})
|
||||
.match(Tick.class, message -> {
|
||||
// do something useful here
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
FirstTick.class,
|
||||
message -> {
|
||||
// do something useful here
|
||||
getTimers().startPeriodicTimer(TICK_KEY, new Tick(), Duration.ofSeconds(1));
|
||||
})
|
||||
.match(
|
||||
Tick.class,
|
||||
message -> {
|
||||
// do something useful here
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#timers
|
||||
// #timers
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package jdocs.actor;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
import akka.actor.TypedActor;
|
||||
import akka.actor.*;
|
||||
import akka.japi.*;
|
||||
|
|
@ -20,184 +20,187 @@ import java.util.List;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
import akka.routing.RoundRobinGroup;
|
||||
//#imports
|
||||
// #imports
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class TypedActorDocTest extends AbstractJavaTest {
|
||||
Object someReference = null;
|
||||
ActorSystem system = null;
|
||||
Object someReference = null;
|
||||
ActorSystem system = null;
|
||||
|
||||
static
|
||||
//#typed-actor-iface
|
||||
public interface Squarer {
|
||||
//#typed-actor-iface-methods
|
||||
void squareDontCare(int i); //fire-forget
|
||||
public
|
||||
// #typed-actor-iface
|
||||
static interface Squarer {
|
||||
// #typed-actor-iface-methods
|
||||
void squareDontCare(int i); // fire-forget
|
||||
|
||||
Future<Integer> square(int i); //non-blocking send-request-reply
|
||||
Future<Integer> square(int i); // non-blocking send-request-reply
|
||||
|
||||
Option<Integer> squareNowPlease(int i);//blocking send-request-reply
|
||||
Option<Integer> squareNowPlease(int i); // blocking send-request-reply
|
||||
|
||||
int squareNow(int i); //blocking send-request-reply
|
||||
//#typed-actor-iface-methods
|
||||
int squareNow(int i); // blocking send-request-reply
|
||||
// #typed-actor-iface-methods
|
||||
}
|
||||
// #typed-actor-iface
|
||||
|
||||
static
|
||||
// #typed-actor-impl
|
||||
class SquarerImpl implements Squarer {
|
||||
private String name;
|
||||
|
||||
public SquarerImpl() {
|
||||
this.name = "default";
|
||||
}
|
||||
//#typed-actor-iface
|
||||
|
||||
static
|
||||
//#typed-actor-impl
|
||||
class SquarerImpl implements Squarer {
|
||||
private String name;
|
||||
|
||||
public SquarerImpl() {
|
||||
this.name = "default";
|
||||
}
|
||||
|
||||
public SquarerImpl(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
//#typed-actor-impl-methods
|
||||
|
||||
public void squareDontCare(int i) {
|
||||
int sq = i * i; //Nobody cares :(
|
||||
}
|
||||
|
||||
public Future<Integer> square(int i) {
|
||||
return Futures.successful(i * i);
|
||||
}
|
||||
|
||||
public Option<Integer> squareNowPlease(int i) {
|
||||
return Option.some(i * i);
|
||||
}
|
||||
|
||||
public int squareNow(int i) {
|
||||
return i * i;
|
||||
}
|
||||
//#typed-actor-impl-methods
|
||||
public SquarerImpl(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
//#typed-actor-impl
|
||||
|
||||
@Test public void mustGetTheTypedActorExtension() {
|
||||
// #typed-actor-impl-methods
|
||||
|
||||
public void squareDontCare(int i) {
|
||||
int sq = i * i; // Nobody cares :(
|
||||
}
|
||||
|
||||
public Future<Integer> square(int i) {
|
||||
return Futures.successful(i * i);
|
||||
}
|
||||
|
||||
public Option<Integer> squareNowPlease(int i) {
|
||||
return Option.some(i * i);
|
||||
}
|
||||
|
||||
public int squareNow(int i) {
|
||||
return i * i;
|
||||
}
|
||||
// #typed-actor-impl-methods
|
||||
}
|
||||
// #typed-actor-impl
|
||||
|
||||
@Test
|
||||
public void mustGetTheTypedActorExtension() {
|
||||
|
||||
try {
|
||||
//#typed-actor-extension-tools
|
||||
// #typed-actor-extension-tools
|
||||
|
||||
//Returns the Typed Actor Extension
|
||||
// Returns the Typed Actor Extension
|
||||
TypedActorExtension extension =
|
||||
TypedActor.get(system); //system is an instance of ActorSystem
|
||||
TypedActor.get(system); // system is an instance of ActorSystem
|
||||
|
||||
//Returns whether the reference is a Typed Actor Proxy or not
|
||||
// Returns whether the reference is a Typed Actor Proxy or not
|
||||
TypedActor.get(system).isTypedActor(someReference);
|
||||
|
||||
//Returns the backing Akka Actor behind an external Typed Actor Proxy
|
||||
// Returns the backing Akka Actor behind an external Typed Actor Proxy
|
||||
TypedActor.get(system).getActorRefFor(someReference);
|
||||
|
||||
//Returns the current ActorContext,
|
||||
// Returns the current ActorContext,
|
||||
// method only valid within methods of a TypedActor implementation
|
||||
ActorContext context = TypedActor.context();
|
||||
|
||||
//Returns the external proxy of the current Typed Actor,
|
||||
// Returns the external proxy of the current Typed Actor,
|
||||
// method only valid within methods of a TypedActor implementation
|
||||
Squarer sq = TypedActor.<Squarer>self();
|
||||
|
||||
//Returns a contextual instance of the Typed Actor Extension
|
||||
//this means that if you create other Typed Actors with this,
|
||||
//they will become children to the current Typed Actor.
|
||||
// Returns a contextual instance of the Typed Actor Extension
|
||||
// this means that if you create other Typed Actors with this,
|
||||
// they will become children to the current Typed Actor.
|
||||
TypedActor.get(TypedActor.context());
|
||||
|
||||
//#typed-actor-extension-tools
|
||||
// #typed-actor-extension-tools
|
||||
} catch (Exception e) {
|
||||
//dun care
|
||||
}
|
||||
}
|
||||
@Test public void createATypedActor() {
|
||||
try {
|
||||
//#typed-actor-create1
|
||||
Squarer mySquarer =
|
||||
TypedActor.get(system).typedActorOf(
|
||||
new TypedProps<SquarerImpl>(Squarer.class, SquarerImpl.class));
|
||||
//#typed-actor-create1
|
||||
//#typed-actor-create2
|
||||
Squarer otherSquarer =
|
||||
TypedActor.get(system).typedActorOf(
|
||||
new TypedProps<SquarerImpl>(Squarer.class,
|
||||
new Creator<SquarerImpl>() {
|
||||
public SquarerImpl create() { return new SquarerImpl("foo"); }
|
||||
}),
|
||||
"name");
|
||||
//#typed-actor-create2
|
||||
|
||||
//#typed-actor-calls
|
||||
//#typed-actor-call-oneway
|
||||
mySquarer.squareDontCare(10);
|
||||
//#typed-actor-call-oneway
|
||||
|
||||
//#typed-actor-call-future
|
||||
Future<Integer> fSquare = mySquarer.square(10); //A Future[Int]
|
||||
//#typed-actor-call-future
|
||||
|
||||
//#typed-actor-call-option
|
||||
Option<Integer> oSquare = mySquarer.squareNowPlease(10); //Option[Int]
|
||||
//#typed-actor-call-option
|
||||
|
||||
//#typed-actor-call-strict
|
||||
int iSquare = mySquarer.squareNow(10); //Int
|
||||
//#typed-actor-call-strict
|
||||
//#typed-actor-calls
|
||||
|
||||
assertEquals(100, Await.result(fSquare,
|
||||
Duration.create(3, TimeUnit.SECONDS)).intValue());
|
||||
|
||||
assertEquals(100, oSquare.get().intValue());
|
||||
|
||||
assertEquals(100, iSquare);
|
||||
|
||||
//#typed-actor-stop
|
||||
TypedActor.get(system).stop(mySquarer);
|
||||
//#typed-actor-stop
|
||||
|
||||
//#typed-actor-poisonpill
|
||||
TypedActor.get(system).poisonPill(otherSquarer);
|
||||
//#typed-actor-poisonpill
|
||||
} catch(Exception e) {
|
||||
//Ignore
|
||||
// dun care
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void createHierarchies() {
|
||||
@Test
|
||||
public void createATypedActor() {
|
||||
try {
|
||||
//#typed-actor-hierarchy
|
||||
Squarer childSquarer =
|
||||
TypedActor.get(TypedActor.context()).
|
||||
typedActorOf(
|
||||
new TypedProps<SquarerImpl>(Squarer.class, SquarerImpl.class)
|
||||
);
|
||||
//Use "childSquarer" as a Squarer
|
||||
//#typed-actor-hierarchy
|
||||
// #typed-actor-create1
|
||||
Squarer mySquarer =
|
||||
TypedActor.get(system)
|
||||
.typedActorOf(new TypedProps<SquarerImpl>(Squarer.class, SquarerImpl.class));
|
||||
// #typed-actor-create1
|
||||
// #typed-actor-create2
|
||||
Squarer otherSquarer =
|
||||
TypedActor.get(system)
|
||||
.typedActorOf(
|
||||
new TypedProps<SquarerImpl>(
|
||||
Squarer.class,
|
||||
new Creator<SquarerImpl>() {
|
||||
public SquarerImpl create() {
|
||||
return new SquarerImpl("foo");
|
||||
}
|
||||
}),
|
||||
"name");
|
||||
// #typed-actor-create2
|
||||
|
||||
// #typed-actor-calls
|
||||
// #typed-actor-call-oneway
|
||||
mySquarer.squareDontCare(10);
|
||||
// #typed-actor-call-oneway
|
||||
|
||||
// #typed-actor-call-future
|
||||
Future<Integer> fSquare = mySquarer.square(10); // A Future[Int]
|
||||
// #typed-actor-call-future
|
||||
|
||||
// #typed-actor-call-option
|
||||
Option<Integer> oSquare = mySquarer.squareNowPlease(10); // Option[Int]
|
||||
// #typed-actor-call-option
|
||||
|
||||
// #typed-actor-call-strict
|
||||
int iSquare = mySquarer.squareNow(10); // Int
|
||||
// #typed-actor-call-strict
|
||||
// #typed-actor-calls
|
||||
|
||||
assertEquals(100, Await.result(fSquare, Duration.create(3, TimeUnit.SECONDS)).intValue());
|
||||
|
||||
assertEquals(100, oSquare.get().intValue());
|
||||
|
||||
assertEquals(100, iSquare);
|
||||
|
||||
// #typed-actor-stop
|
||||
TypedActor.get(system).stop(mySquarer);
|
||||
// #typed-actor-stop
|
||||
|
||||
// #typed-actor-poisonpill
|
||||
TypedActor.get(system).poisonPill(otherSquarer);
|
||||
// #typed-actor-poisonpill
|
||||
} catch (Exception e) {
|
||||
//dun care
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void proxyAnyActorRef() {
|
||||
@Test
|
||||
public void createHierarchies() {
|
||||
try {
|
||||
final ActorRef actorRefToRemoteActor = system.deadLetters();
|
||||
//#typed-actor-remote
|
||||
Squarer typedActor =
|
||||
TypedActor.get(system).
|
||||
typedActorOf(
|
||||
new TypedProps<Squarer>(Squarer.class),
|
||||
actorRefToRemoteActor
|
||||
);
|
||||
//Use "typedActor" as a FooBar
|
||||
//#typed-actor-remote
|
||||
// #typed-actor-hierarchy
|
||||
Squarer childSquarer =
|
||||
TypedActor.get(TypedActor.context())
|
||||
.typedActorOf(new TypedProps<SquarerImpl>(Squarer.class, SquarerImpl.class));
|
||||
// Use "childSquarer" as a Squarer
|
||||
// #typed-actor-hierarchy
|
||||
} catch (Exception e) {
|
||||
//dun care
|
||||
// dun care
|
||||
}
|
||||
}
|
||||
|
||||
//#typed-router-types
|
||||
@Test
|
||||
public void proxyAnyActorRef() {
|
||||
try {
|
||||
final ActorRef actorRefToRemoteActor = system.deadLetters();
|
||||
// #typed-actor-remote
|
||||
Squarer typedActor =
|
||||
TypedActor.get(system)
|
||||
.typedActorOf(new TypedProps<Squarer>(Squarer.class), actorRefToRemoteActor);
|
||||
// Use "typedActor" as a FooBar
|
||||
// #typed-actor-remote
|
||||
} catch (Exception e) {
|
||||
// dun care
|
||||
}
|
||||
}
|
||||
|
||||
// #typed-router-types
|
||||
interface HasName {
|
||||
String name();
|
||||
}
|
||||
|
|
@ -205,22 +208,23 @@ public class TypedActorDocTest extends AbstractJavaTest {
|
|||
class Named implements HasName {
|
||||
private int id = new Random().nextInt(1024);
|
||||
|
||||
@Override public String name() { return "name-" + id; }
|
||||
@Override
|
||||
public String name() {
|
||||
return "name-" + id;
|
||||
}
|
||||
}
|
||||
//#typed-router-types
|
||||
// #typed-router-types
|
||||
|
||||
|
||||
@Test public void typedRouterPattern() {
|
||||
@Test
|
||||
public void typedRouterPattern() {
|
||||
try {
|
||||
//#typed-router
|
||||
// #typed-router
|
||||
// prepare routees
|
||||
TypedActorExtension typed = TypedActor.get(system);
|
||||
|
||||
Named named1 =
|
||||
typed.typedActorOf(new TypedProps<Named>(Named.class));
|
||||
Named named1 = typed.typedActorOf(new TypedProps<Named>(Named.class));
|
||||
|
||||
Named named2 =
|
||||
typed.typedActorOf(new TypedProps<Named>(Named.class));
|
||||
Named named2 = typed.typedActorOf(new TypedProps<Named>(Named.class));
|
||||
|
||||
List<Named> routees = new ArrayList<Named>();
|
||||
routees.add(named1);
|
||||
|
|
@ -241,13 +245,13 @@ public class TypedActorDocTest extends AbstractJavaTest {
|
|||
System.out.println("actor was: " + typedRouter.name()); // name-243
|
||||
System.out.println("actor was: " + typedRouter.name()); // name-614
|
||||
|
||||
//#typed-router
|
||||
// #typed-router
|
||||
typed.poisonPill(named1);
|
||||
typed.poisonPill(named2);
|
||||
typed.poisonPill(typedRouter);
|
||||
|
||||
} catch (Exception e) {
|
||||
//dun care
|
||||
// dun care
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package jdocs.actor.fsm;
|
||||
|
||||
//#simple-imports
|
||||
// #simple-imports
|
||||
import akka.actor.AbstractFSM;
|
||||
import akka.actor.ActorRef;
|
||||
import akka.japi.pf.UnitMatch;
|
||||
|
|
@ -12,7 +12,7 @@ import java.util.Arrays;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.time.Duration;
|
||||
//#simple-imports
|
||||
// #simple-imports
|
||||
|
||||
import static jdocs.actor.fsm.Buncher.Data;
|
||||
import static jdocs.actor.fsm.Buncher.State.*;
|
||||
|
|
@ -20,75 +20,100 @@ import static jdocs.actor.fsm.Buncher.State;
|
|||
import static jdocs.actor.fsm.Buncher.Uninitialized.*;
|
||||
import static jdocs.actor.fsm.Events.*;
|
||||
|
||||
//#simple-fsm
|
||||
// #simple-fsm
|
||||
public class Buncher extends AbstractFSM<State, Data> {
|
||||
{
|
||||
//#fsm-body
|
||||
// #fsm-body
|
||||
startWith(Idle, Uninitialized);
|
||||
|
||||
//#when-syntax
|
||||
when(Idle,
|
||||
matchEvent(SetTarget.class, Uninitialized.class,
|
||||
(setTarget, uninitialized) ->
|
||||
stay().using(new Todo(setTarget.getRef(), new LinkedList<>()))));
|
||||
//#when-syntax
|
||||
// #when-syntax
|
||||
when(
|
||||
Idle,
|
||||
matchEvent(
|
||||
SetTarget.class,
|
||||
Uninitialized.class,
|
||||
(setTarget, uninitialized) ->
|
||||
stay().using(new Todo(setTarget.getRef(), new LinkedList<>()))));
|
||||
// #when-syntax
|
||||
|
||||
//#transition-elided
|
||||
// #transition-elided
|
||||
onTransition(
|
||||
matchState(Active, Idle, () -> {
|
||||
// reuse this matcher
|
||||
final UnitMatch<Data> m = UnitMatch.create(
|
||||
matchData(Todo.class,
|
||||
todo -> todo.getTarget().tell(new Batch(todo.getQueue()), getSelf())));
|
||||
m.match(stateData());
|
||||
}).
|
||||
state(Idle, Active, () -> {/* Do something here */}));
|
||||
//#transition-elided
|
||||
matchState(
|
||||
Active,
|
||||
Idle,
|
||||
() -> {
|
||||
// reuse this matcher
|
||||
final UnitMatch<Data> m =
|
||||
UnitMatch.create(
|
||||
matchData(
|
||||
Todo.class,
|
||||
todo ->
|
||||
todo.getTarget().tell(new Batch(todo.getQueue()), getSelf())));
|
||||
m.match(stateData());
|
||||
})
|
||||
.state(
|
||||
Idle,
|
||||
Active,
|
||||
() -> {
|
||||
/* Do something here */
|
||||
}));
|
||||
// #transition-elided
|
||||
|
||||
when(Active, Duration.ofSeconds(1L),
|
||||
matchEvent(Arrays.asList(Flush.class, StateTimeout()), Todo.class,
|
||||
(event, todo) -> goTo(Idle).using(todo.copy(new LinkedList<>()))));
|
||||
when(
|
||||
Active,
|
||||
Duration.ofSeconds(1L),
|
||||
matchEvent(
|
||||
Arrays.asList(Flush.class, StateTimeout()),
|
||||
Todo.class,
|
||||
(event, todo) -> goTo(Idle).using(todo.copy(new LinkedList<>()))));
|
||||
|
||||
//#unhandled-elided
|
||||
// #unhandled-elided
|
||||
whenUnhandled(
|
||||
matchEvent(Queue.class, Todo.class,
|
||||
(queue, todo) -> goTo(Active).using(todo.addElement(queue.getObj()))).
|
||||
anyEvent((event, state) -> {
|
||||
log().warning("received unhandled request {} in state {}/{}",
|
||||
event, stateName(), state);
|
||||
return stay();
|
||||
}));
|
||||
//#unhandled-elided
|
||||
matchEvent(
|
||||
Queue.class,
|
||||
Todo.class,
|
||||
(queue, todo) -> goTo(Active).using(todo.addElement(queue.getObj())))
|
||||
.anyEvent(
|
||||
(event, state) -> {
|
||||
log()
|
||||
.warning(
|
||||
"received unhandled request {} in state {}/{}",
|
||||
event,
|
||||
stateName(),
|
||||
state);
|
||||
return stay();
|
||||
}));
|
||||
// #unhandled-elided
|
||||
|
||||
initialize();
|
||||
//#fsm-body
|
||||
// #fsm-body
|
||||
}
|
||||
//#simple-fsm
|
||||
// #simple-fsm
|
||||
|
||||
static
|
||||
//#simple-state
|
||||
// #simple-state
|
||||
// states
|
||||
enum State {
|
||||
Idle, Active
|
||||
Idle,
|
||||
Active
|
||||
}
|
||||
|
||||
//#simple-state
|
||||
// #simple-state
|
||||
static
|
||||
//#simple-state
|
||||
// #simple-state
|
||||
// state data
|
||||
interface Data {
|
||||
}
|
||||
interface Data {}
|
||||
|
||||
//#simple-state
|
||||
// #simple-state
|
||||
static
|
||||
//#simple-state
|
||||
// #simple-state
|
||||
enum Uninitialized implements Data {
|
||||
Uninitialized
|
||||
}
|
||||
|
||||
//#simple-state
|
||||
// #simple-state
|
||||
static
|
||||
//#simple-state
|
||||
// #simple-state
|
||||
final class Todo implements Data {
|
||||
private final ActorRef target;
|
||||
private final List<Object> queue;
|
||||
|
|
@ -105,14 +130,11 @@ public class Buncher extends AbstractFSM<State, Data> {
|
|||
public List<Object> getQueue() {
|
||||
return queue;
|
||||
}
|
||||
//#boilerplate
|
||||
// #boilerplate
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Todo{" +
|
||||
"target=" + target +
|
||||
", queue=" + queue +
|
||||
'}';
|
||||
return "Todo{" + "target=" + target + ", queue=" + queue + '}';
|
||||
}
|
||||
|
||||
public Todo addElement(Object element) {
|
||||
|
|
@ -128,9 +150,9 @@ public class Buncher extends AbstractFSM<State, Data> {
|
|||
public Todo copy(ActorRef target) {
|
||||
return new Todo(target, this.queue);
|
||||
}
|
||||
//#boilerplate
|
||||
// #boilerplate
|
||||
}
|
||||
//#simple-state
|
||||
//#simple-fsm
|
||||
// #simple-state
|
||||
// #simple-fsm
|
||||
}
|
||||
//#simple-fsm
|
||||
// #simple-fsm
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import static jdocs.actor.fsm.Events.Queue;
|
|||
import static jdocs.actor.fsm.Events.SetTarget;
|
||||
import static jdocs.actor.fsm.Events.Flush.Flush;
|
||||
|
||||
//#test-code
|
||||
// #test-code
|
||||
public class BuncherTest extends AbstractJavaTest {
|
||||
|
||||
static ActorSystem system;
|
||||
|
|
@ -37,42 +37,44 @@ public class BuncherTest extends AbstractJavaTest {
|
|||
|
||||
@Test
|
||||
public void testBuncherActorBatchesCorrectly() {
|
||||
new TestKit(system) {{
|
||||
final ActorRef buncher =
|
||||
system.actorOf(Props.create(Buncher.class));
|
||||
final ActorRef probe = getRef();
|
||||
new TestKit(system) {
|
||||
{
|
||||
final ActorRef buncher = system.actorOf(Props.create(Buncher.class));
|
||||
final ActorRef probe = getRef();
|
||||
|
||||
buncher.tell(new SetTarget(probe), probe);
|
||||
buncher.tell(new Queue(42), probe);
|
||||
buncher.tell(new Queue(43), probe);
|
||||
LinkedList<Object> list1 = new LinkedList<>();
|
||||
list1.add(42);
|
||||
list1.add(43);
|
||||
expectMsgEquals(new Batch(list1));
|
||||
buncher.tell(new Queue(44), probe);
|
||||
buncher.tell(Flush, probe);
|
||||
buncher.tell(new Queue(45), probe);
|
||||
LinkedList<Object> list2 = new LinkedList<>();
|
||||
list2.add(44);
|
||||
expectMsgEquals(new Batch(list2));
|
||||
LinkedList<Object> list3 = new LinkedList<>();
|
||||
list3.add(45);
|
||||
expectMsgEquals(new Batch(list3));
|
||||
system.stop(buncher);
|
||||
}};
|
||||
buncher.tell(new SetTarget(probe), probe);
|
||||
buncher.tell(new Queue(42), probe);
|
||||
buncher.tell(new Queue(43), probe);
|
||||
LinkedList<Object> list1 = new LinkedList<>();
|
||||
list1.add(42);
|
||||
list1.add(43);
|
||||
expectMsgEquals(new Batch(list1));
|
||||
buncher.tell(new Queue(44), probe);
|
||||
buncher.tell(Flush, probe);
|
||||
buncher.tell(new Queue(45), probe);
|
||||
LinkedList<Object> list2 = new LinkedList<>();
|
||||
list2.add(44);
|
||||
expectMsgEquals(new Batch(list2));
|
||||
LinkedList<Object> list3 = new LinkedList<>();
|
||||
list3.add(45);
|
||||
expectMsgEquals(new Batch(list3));
|
||||
system.stop(buncher);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuncherActorDoesntBatchUninitialized() {
|
||||
new TestKit(system) {{
|
||||
final ActorRef buncher =
|
||||
system.actorOf(Props.create(Buncher.class));
|
||||
final ActorRef probe = getRef();
|
||||
new TestKit(system) {
|
||||
{
|
||||
final ActorRef buncher = system.actorOf(Props.create(Buncher.class));
|
||||
final ActorRef probe = getRef();
|
||||
|
||||
buncher.tell(new Queue(42), probe);
|
||||
expectNoMessage();
|
||||
system.stop(buncher);
|
||||
}};
|
||||
buncher.tell(new Queue(42), probe);
|
||||
expectNoMessage();
|
||||
system.stop(buncher);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
//#test-code
|
||||
// #test-code
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import java.util.List;
|
|||
|
||||
public class Events {
|
||||
|
||||
static
|
||||
//#simple-events
|
||||
public final class SetTarget {
|
||||
public
|
||||
// #simple-events
|
||||
static final class SetTarget {
|
||||
private final ActorRef ref;
|
||||
|
||||
public SetTarget(ActorRef ref) {
|
||||
|
|
@ -21,21 +21,19 @@ public class Events {
|
|||
public ActorRef getRef() {
|
||||
return ref;
|
||||
}
|
||||
//#boilerplate
|
||||
// #boilerplate
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SetTarget{" +
|
||||
"ref=" + ref +
|
||||
'}';
|
||||
return "SetTarget{" + "ref=" + ref + '}';
|
||||
}
|
||||
//#boilerplate
|
||||
// #boilerplate
|
||||
}
|
||||
|
||||
//#simple-events
|
||||
static
|
||||
//#simple-events
|
||||
public final class Queue {
|
||||
// #simple-events
|
||||
public
|
||||
// #simple-events
|
||||
static final class Queue {
|
||||
private final Object obj;
|
||||
|
||||
public Queue(Object obj) {
|
||||
|
|
@ -45,21 +43,19 @@ public class Events {
|
|||
public Object getObj() {
|
||||
return obj;
|
||||
}
|
||||
//#boilerplate
|
||||
// #boilerplate
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Queue{" +
|
||||
"obj=" + obj +
|
||||
'}';
|
||||
return "Queue{" + "obj=" + obj + '}';
|
||||
}
|
||||
//#boilerplate
|
||||
// #boilerplate
|
||||
}
|
||||
|
||||
//#simple-events
|
||||
static
|
||||
//#simple-events
|
||||
public final class Batch {
|
||||
// #simple-events
|
||||
public
|
||||
// #simple-events
|
||||
static final class Batch {
|
||||
private final List<Object> list;
|
||||
|
||||
public Batch(List<Object> list) {
|
||||
|
|
@ -69,7 +65,7 @@ public class Events {
|
|||
public List<Object> getList() {
|
||||
return list;
|
||||
}
|
||||
//#boilerplate
|
||||
// #boilerplate
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
|
@ -89,20 +85,25 @@ public class Events {
|
|||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append( "Batch{list=");
|
||||
list.stream().forEachOrdered(e -> { builder.append(e); builder.append(","); });
|
||||
builder.append("Batch{list=");
|
||||
list.stream()
|
||||
.forEachOrdered(
|
||||
e -> {
|
||||
builder.append(e);
|
||||
builder.append(",");
|
||||
});
|
||||
int len = builder.length();
|
||||
builder.replace(len, len, "}");
|
||||
return builder.toString();
|
||||
}
|
||||
//#boilerplate
|
||||
// #boilerplate
|
||||
}
|
||||
|
||||
//#simple-events
|
||||
static
|
||||
//#simple-events
|
||||
public enum Flush {
|
||||
// #simple-events
|
||||
public
|
||||
// #simple-events
|
||||
static enum Flush {
|
||||
Flush
|
||||
}
|
||||
//#simple-events
|
||||
// #simple-events
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,126 +54,166 @@ public class FSMDocTest extends AbstractJavaTest {
|
|||
|
||||
public static class DummyFSM extends AbstractFSM<StateType, Integer> {
|
||||
Integer newData = 42;
|
||||
//#alt-transition-syntax
|
||||
// #alt-transition-syntax
|
||||
public void handler(StateType from, StateType to) {
|
||||
// handle transition here
|
||||
}
|
||||
|
||||
//#alt-transition-syntax
|
||||
// #alt-transition-syntax
|
||||
{
|
||||
//#modifier-syntax
|
||||
when(SomeState, matchAnyEvent((msg, data) -> {
|
||||
return goTo(Processing).using(newData).
|
||||
forMax(Duration.ofSeconds(5)).replying(WillDo);
|
||||
}));
|
||||
//#modifier-syntax
|
||||
// #modifier-syntax
|
||||
when(
|
||||
SomeState,
|
||||
matchAnyEvent(
|
||||
(msg, data) -> {
|
||||
return goTo(Processing)
|
||||
.using(newData)
|
||||
.forMax(Duration.ofSeconds(5))
|
||||
.replying(WillDo);
|
||||
}));
|
||||
// #modifier-syntax
|
||||
|
||||
//#NullFunction
|
||||
when(SomeState, AbstractFSM.NullFunction());
|
||||
//#NullFunction
|
||||
// #NullFunction
|
||||
when(SomeState, AbstractFSM.NullFunction());
|
||||
// #NullFunction
|
||||
|
||||
//#transition-syntax
|
||||
onTransition(
|
||||
matchState(Idle, Active, () -> setTimer("timeout",
|
||||
Tick, Duration.ofSeconds(1L), true)).
|
||||
state(Active, null, () -> cancelTimer("timeout")).
|
||||
state(null, Idle, (f, t) -> log().info("entering Idle from " + f)));
|
||||
//#transition-syntax
|
||||
// #transition-syntax
|
||||
onTransition(
|
||||
matchState(Idle, Active, () -> setTimer("timeout", Tick, Duration.ofSeconds(1L), true))
|
||||
.state(Active, null, () -> cancelTimer("timeout"))
|
||||
.state(null, Idle, (f, t) -> log().info("entering Idle from " + f)));
|
||||
// #transition-syntax
|
||||
|
||||
//#alt-transition-syntax
|
||||
onTransition(this::handler);
|
||||
//#alt-transition-syntax
|
||||
// #alt-transition-syntax
|
||||
onTransition(this::handler);
|
||||
// #alt-transition-syntax
|
||||
|
||||
//#stop-syntax
|
||||
when(Error, matchEventEquals("stop", (event, data) -> {
|
||||
// do cleanup ...
|
||||
return stop();
|
||||
}));
|
||||
//#stop-syntax
|
||||
// #stop-syntax
|
||||
when(
|
||||
Error,
|
||||
matchEventEquals(
|
||||
"stop",
|
||||
(event, data) -> {
|
||||
// do cleanup ...
|
||||
return stop();
|
||||
}));
|
||||
// #stop-syntax
|
||||
|
||||
//#termination-syntax
|
||||
onTermination(
|
||||
matchStop(Normal(),
|
||||
(state, data) -> {/* Do something here */}).
|
||||
stop(Shutdown(),
|
||||
(state, data) -> {/* Do something here */}).
|
||||
stop(Failure.class,
|
||||
(reason, state, data) -> {/* Do something here */}));
|
||||
//#termination-syntax
|
||||
// #termination-syntax
|
||||
onTermination(
|
||||
matchStop(
|
||||
Normal(),
|
||||
(state, data) -> {
|
||||
/* Do something here */
|
||||
})
|
||||
.stop(
|
||||
Shutdown(),
|
||||
(state, data) -> {
|
||||
/* Do something here */
|
||||
})
|
||||
.stop(
|
||||
Failure.class,
|
||||
(reason, state, data) -> {
|
||||
/* Do something here */
|
||||
}));
|
||||
// #termination-syntax
|
||||
|
||||
//#unhandled-syntax
|
||||
whenUnhandled(
|
||||
matchEvent(X.class, (x, data) -> {
|
||||
log().info("Received unhandled event: " + x);
|
||||
return stay();
|
||||
}).
|
||||
anyEvent((event, data) -> {
|
||||
log().warning("Received unknown event: " + event);
|
||||
return goTo(Error);
|
||||
}));
|
||||
}
|
||||
//#unhandled-syntax
|
||||
// #unhandled-syntax
|
||||
whenUnhandled(
|
||||
matchEvent(
|
||||
X.class,
|
||||
(x, data) -> {
|
||||
log().info("Received unhandled event: " + x);
|
||||
return stay();
|
||||
})
|
||||
.anyEvent(
|
||||
(event, data) -> {
|
||||
log().warning("Received unknown event: " + event);
|
||||
return goTo(Error);
|
||||
}));
|
||||
}
|
||||
// #unhandled-syntax
|
||||
}
|
||||
|
||||
static
|
||||
//#logging-fsm
|
||||
public class MyFSM extends AbstractLoggingFSM<StateType, Data> {
|
||||
//#body-elided
|
||||
//#logging-fsm
|
||||
public
|
||||
// #logging-fsm
|
||||
static class MyFSM extends AbstractLoggingFSM<StateType, Data> {
|
||||
// #body-elided
|
||||
// #logging-fsm
|
||||
ActorRef target = null;
|
||||
//#logging-fsm
|
||||
// #logging-fsm
|
||||
@Override
|
||||
public int logDepth() { return 12; }
|
||||
public int logDepth() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
{
|
||||
onTermination(
|
||||
matchStop(Failure.class, (reason, state, data) -> {
|
||||
String lastEvents = getLog().mkString("\n\t");
|
||||
log().warning("Failure in state " + state + " with data " + data + "\n" +
|
||||
"Events leading up to this point:\n\t" + lastEvents);
|
||||
//#logging-fsm
|
||||
target.tell(reason.cause(), getSelf());
|
||||
target.tell(state, getSelf());
|
||||
target.tell(data, getSelf());
|
||||
target.tell(lastEvents, getSelf());
|
||||
//#logging-fsm
|
||||
})
|
||||
);
|
||||
//...
|
||||
//#logging-fsm
|
||||
matchStop(
|
||||
Failure.class,
|
||||
(reason, state, data) -> {
|
||||
String lastEvents = getLog().mkString("\n\t");
|
||||
log()
|
||||
.warning(
|
||||
"Failure in state "
|
||||
+ state
|
||||
+ " with data "
|
||||
+ data
|
||||
+ "\n"
|
||||
+ "Events leading up to this point:\n\t"
|
||||
+ lastEvents);
|
||||
// #logging-fsm
|
||||
target.tell(reason.cause(), getSelf());
|
||||
target.tell(state, getSelf());
|
||||
target.tell(data, getSelf());
|
||||
target.tell(lastEvents, getSelf());
|
||||
// #logging-fsm
|
||||
}));
|
||||
// ...
|
||||
// #logging-fsm
|
||||
startWith(SomeState, Data.Foo);
|
||||
when(SomeState, matchEvent(ActorRef.class, Data.class, (ref, data) -> {
|
||||
target = ref;
|
||||
target.tell("going active", getSelf());
|
||||
return goTo(Active);
|
||||
}));
|
||||
when(Active, matchEventEquals("stop", (event, data) -> {
|
||||
target.tell("stopping", getSelf());
|
||||
return stop(new Failure("This is not the error you're looking for"));
|
||||
}));
|
||||
when(
|
||||
SomeState,
|
||||
matchEvent(
|
||||
ActorRef.class,
|
||||
Data.class,
|
||||
(ref, data) -> {
|
||||
target = ref;
|
||||
target.tell("going active", getSelf());
|
||||
return goTo(Active);
|
||||
}));
|
||||
when(
|
||||
Active,
|
||||
matchEventEquals(
|
||||
"stop",
|
||||
(event, data) -> {
|
||||
target.tell("stopping", getSelf());
|
||||
return stop(new Failure("This is not the error you're looking for"));
|
||||
}));
|
||||
initialize();
|
||||
//#logging-fsm
|
||||
// #logging-fsm
|
||||
}
|
||||
//#body-elided
|
||||
// #body-elided
|
||||
}
|
||||
//#logging-fsm
|
||||
// #logging-fsm
|
||||
|
||||
@Test
|
||||
public void testLoggingFSM()
|
||||
{
|
||||
new TestKit(system) {{
|
||||
final ActorRef logger =
|
||||
system.actorOf(Props.create(MyFSM.class));
|
||||
final ActorRef probe = getRef();
|
||||
public void testLoggingFSM() {
|
||||
new TestKit(system) {
|
||||
{
|
||||
final ActorRef logger = system.actorOf(Props.create(MyFSM.class));
|
||||
final ActorRef probe = getRef();
|
||||
|
||||
logger.tell(probe, probe);
|
||||
expectMsgEquals("going active");
|
||||
logger.tell("stop", probe);
|
||||
expectMsgEquals("stopping");
|
||||
expectMsgEquals("This is not the error you're looking for");
|
||||
expectMsgEquals(Active);
|
||||
expectMsgEquals(Data.Foo);
|
||||
String msg = expectMsgClass(String.class);
|
||||
assertTrue(msg.startsWith("LogEntry(SomeState,Foo,Actor[akka://FSMDocTest/system/"));
|
||||
}};
|
||||
logger.tell(probe, probe);
|
||||
expectMsgEquals("going active");
|
||||
logger.tell("stop", probe);
|
||||
expectMsgEquals("stopping");
|
||||
expectMsgEquals("This is not the error you're looking for");
|
||||
expectMsgEquals(Active);
|
||||
expectMsgEquals(Data.Foo);
|
||||
String msg = expectMsgClass(String.class);
|
||||
assertTrue(msg.startsWith("LogEntry(SomeState,Foo,Actor[akka://FSMDocTest/system/"));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,41 +16,40 @@ import scala.Option;
|
|||
import java.time.Duration;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
|
||||
public class DnsCompileOnlyDocTest {
|
||||
public static void example() {
|
||||
ActorSystem system = ActorSystem.create();
|
||||
public static void example() {
|
||||
ActorSystem system = ActorSystem.create();
|
||||
|
||||
ActorRef actorRef = null;
|
||||
final Duration timeout = Duration.ofMillis(1000L);
|
||||
ActorRef actorRef = null;
|
||||
final Duration timeout = Duration.ofMillis(1000L);
|
||||
|
||||
//#resolve
|
||||
Option<Dns.Resolved> initial = Dns.get(system).cache().resolve("google.com", system, actorRef);
|
||||
Option<Dns.Resolved> cached = Dns.get(system).cache().cached("google.com");
|
||||
//#resolve
|
||||
|
||||
{
|
||||
//#actor-api-inet-address
|
||||
final ActorRef dnsManager = Dns.get(system).manager();
|
||||
CompletionStage<Object> resolved = ask(dnsManager, new Dns.Resolve("google.com"), timeout);
|
||||
//#actor-api-inet-address
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
//#actor-api-async
|
||||
final ActorRef dnsManager = Dns.get(system).manager();
|
||||
CompletionStage<Object> resolved = ask(dnsManager, DnsProtocol.resolve("google.com"), timeout);
|
||||
//#actor-api-async
|
||||
}
|
||||
|
||||
{
|
||||
//#srv
|
||||
final ActorRef dnsManager = Dns.get(system).manager();
|
||||
CompletionStage<Object> resolved = ask(dnsManager, DnsProtocol.resolve("google.com", DnsProtocol.srvRequestType()), timeout);
|
||||
//#srv
|
||||
}
|
||||
// #resolve
|
||||
Option<Dns.Resolved> initial = Dns.get(system).cache().resolve("google.com", system, actorRef);
|
||||
Option<Dns.Resolved> cached = Dns.get(system).cache().cached("google.com");
|
||||
// #resolve
|
||||
|
||||
{
|
||||
// #actor-api-inet-address
|
||||
final ActorRef dnsManager = Dns.get(system).manager();
|
||||
CompletionStage<Object> resolved = ask(dnsManager, new Dns.Resolve("google.com"), timeout);
|
||||
// #actor-api-inet-address
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
// #actor-api-async
|
||||
final ActorRef dnsManager = Dns.get(system).manager();
|
||||
CompletionStage<Object> resolved =
|
||||
ask(dnsManager, DnsProtocol.resolve("google.com"), timeout);
|
||||
// #actor-api-async
|
||||
}
|
||||
|
||||
{
|
||||
// #srv
|
||||
final ActorRef dnsManager = Dns.get(system).manager();
|
||||
CompletionStage<Object> resolved =
|
||||
ask(dnsManager, DnsProtocol.resolve("google.com", DnsProtocol.srvRequestType()), timeout);
|
||||
// #srv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,19 +11,19 @@ import org.junit.Test;
|
|||
import scala.concurrent.Await;
|
||||
import scala.concurrent.duration.Duration;
|
||||
|
||||
//#import-agent
|
||||
import scala.concurrent.ExecutionContext;
|
||||
import akka.agent.Agent;
|
||||
import akka.dispatch.ExecutionContexts;
|
||||
//#import-agent
|
||||
// #import-agent
|
||||
import scala.concurrent.ExecutionContext;
|
||||
import akka.agent.Agent;
|
||||
import akka.dispatch.ExecutionContexts;
|
||||
// #import-agent
|
||||
|
||||
//#import-function
|
||||
import akka.dispatch.Mapper;
|
||||
//#import-function
|
||||
// #import-function
|
||||
import akka.dispatch.Mapper;
|
||||
// #import-function
|
||||
|
||||
//#import-future
|
||||
import scala.concurrent.Future;
|
||||
//#import-future
|
||||
// #import-future
|
||||
import scala.concurrent.Future;
|
||||
// #import-future
|
||||
|
||||
public class AgentDocTest extends jdocs.AbstractJavaTest {
|
||||
|
||||
|
|
@ -31,86 +31,90 @@ public class AgentDocTest extends jdocs.AbstractJavaTest {
|
|||
|
||||
@Test
|
||||
public void createAndRead() throws Exception {
|
||||
//#create
|
||||
// #create
|
||||
ExecutionContext ec = ExecutionContexts.global();
|
||||
Agent<Integer> agent = Agent.create(5, ec);
|
||||
//#create
|
||||
// #create
|
||||
|
||||
//#read-get
|
||||
// #read-get
|
||||
Integer result = agent.get();
|
||||
//#read-get
|
||||
// #read-get
|
||||
|
||||
//#read-future
|
||||
// #read-future
|
||||
Future<Integer> future = agent.future();
|
||||
//#read-future
|
||||
// #read-future
|
||||
|
||||
assertEquals(result, new Integer(5));
|
||||
assertEquals(Await.result(future, Duration.create(5,"s")), new Integer(5));
|
||||
assertEquals(Await.result(future, Duration.create(5, "s")), new Integer(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendAndSendOffAndReadAwait() throws Exception {
|
||||
Agent<Integer> agent = Agent.create(5, ec);
|
||||
|
||||
//#send
|
||||
// #send
|
||||
// send a value, enqueues this change
|
||||
// of the value of the Agent
|
||||
agent.send(7);
|
||||
|
||||
// send a Mapper, enqueues this change
|
||||
// to the value of the Agent
|
||||
agent.send(new Mapper<Integer, Integer>() {
|
||||
public Integer apply(Integer i) {
|
||||
return i * 2;
|
||||
}
|
||||
});
|
||||
//#send
|
||||
agent.send(
|
||||
new Mapper<Integer, Integer>() {
|
||||
public Integer apply(Integer i) {
|
||||
return i * 2;
|
||||
}
|
||||
});
|
||||
// #send
|
||||
|
||||
Mapper<Integer, Integer> longRunningOrBlockingFunction = new Mapper<Integer, Integer>() {
|
||||
public Integer apply(Integer i) {
|
||||
return i * 1;
|
||||
}
|
||||
};
|
||||
Mapper<Integer, Integer> longRunningOrBlockingFunction =
|
||||
new Mapper<Integer, Integer>() {
|
||||
public Integer apply(Integer i) {
|
||||
return i * 1;
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionContext theExecutionContextToExecuteItIn = ec;
|
||||
//#send-off
|
||||
// #send-off
|
||||
// sendOff a function
|
||||
agent.sendOff(longRunningOrBlockingFunction,
|
||||
theExecutionContextToExecuteItIn);
|
||||
//#send-off
|
||||
agent.sendOff(longRunningOrBlockingFunction, theExecutionContextToExecuteItIn);
|
||||
// #send-off
|
||||
|
||||
assertEquals(Await.result(agent.future(), Duration.create(5,"s")), new Integer(14));
|
||||
assertEquals(Await.result(agent.future(), Duration.create(5, "s")), new Integer(14));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void alterAndAlterOff() throws Exception {
|
||||
@Test
|
||||
public void alterAndAlterOff() throws Exception {
|
||||
Agent<Integer> agent = Agent.create(5, ec);
|
||||
|
||||
//#alter
|
||||
// #alter
|
||||
// alter a value
|
||||
Future<Integer> f1 = agent.alter(7);
|
||||
|
||||
// alter a function (Mapper)
|
||||
Future<Integer> f2 = agent.alter(new Mapper<Integer, Integer>() {
|
||||
public Integer apply(Integer i) {
|
||||
return i * 2;
|
||||
}
|
||||
});
|
||||
//#alter
|
||||
Future<Integer> f2 =
|
||||
agent.alter(
|
||||
new Mapper<Integer, Integer>() {
|
||||
public Integer apply(Integer i) {
|
||||
return i * 2;
|
||||
}
|
||||
});
|
||||
// #alter
|
||||
|
||||
Mapper<Integer, Integer> longRunningOrBlockingFunction = new Mapper<Integer, Integer>() {
|
||||
public Integer apply(Integer i) {
|
||||
Mapper<Integer, Integer> longRunningOrBlockingFunction =
|
||||
new Mapper<Integer, Integer>() {
|
||||
public Integer apply(Integer i) {
|
||||
return i * 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionContext theExecutionContextToExecuteItIn = ec;
|
||||
//#alter-off
|
||||
// #alter-off
|
||||
// alterOff a function (Mapper)
|
||||
Future<Integer> f3 = agent.alterOff(longRunningOrBlockingFunction,
|
||||
theExecutionContextToExecuteItIn);
|
||||
//#alter-off
|
||||
Future<Integer> f3 =
|
||||
agent.alterOff(longRunningOrBlockingFunction, theExecutionContextToExecuteItIn);
|
||||
// #alter-off
|
||||
|
||||
assertEquals(Await.result(f3, Duration.create(5,"s")), new Integer(14));
|
||||
}
|
||||
assertEquals(Await.result(f3, Duration.create(5, "s")), new Integer(14));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,20 +3,20 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#CamelActivation
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import akka.camel.Camel;
|
||||
import akka.camel.CamelExtension;
|
||||
import akka.camel.javaapi.UntypedConsumerActor;
|
||||
import akka.testkit.javadsl.TestKit;
|
||||
import akka.util.Timeout;
|
||||
import jdocs.AbstractJavaTest;
|
||||
import scala.concurrent.Future;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
//#CamelActivation
|
||||
// #CamelActivation
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import akka.camel.Camel;
|
||||
import akka.camel.CamelExtension;
|
||||
import akka.camel.javaapi.UntypedConsumerActor;
|
||||
import akka.testkit.javadsl.TestKit;
|
||||
import akka.util.Timeout;
|
||||
import jdocs.AbstractJavaTest;
|
||||
import scala.concurrent.Future;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
// #CamelActivation
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
|
@ -25,25 +25,25 @@ public class ActivationTestBase extends AbstractJavaTest {
|
|||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testActivation() {
|
||||
//#CamelActivation
|
||||
// #CamelActivation
|
||||
|
||||
// ..
|
||||
ActorSystem system = ActorSystem.create("some-system");
|
||||
Props props = Props.create(MyConsumer.class);
|
||||
ActorRef producer = system.actorOf(props,"myproducer");
|
||||
ActorRef producer = system.actorOf(props, "myproducer");
|
||||
Camel camel = CamelExtension.get(system);
|
||||
// get a future reference to the activation of the endpoint of the Consumer Actor
|
||||
Timeout timeout = new Timeout(Duration.create(10, SECONDS));
|
||||
Future<ActorRef> activationFuture = camel.activationFutureFor(producer,
|
||||
timeout, system.dispatcher());
|
||||
//#CamelActivation
|
||||
//#CamelDeactivation
|
||||
Future<ActorRef> activationFuture =
|
||||
camel.activationFutureFor(producer, timeout, system.dispatcher());
|
||||
// #CamelActivation
|
||||
// #CamelDeactivation
|
||||
// ..
|
||||
system.stop(producer);
|
||||
// get a future reference to the deactivation of the endpoint of the Consumer Actor
|
||||
Future<ActorRef> deactivationFuture = camel.deactivationFutureFor(producer,
|
||||
timeout, system.dispatcher());
|
||||
//#CamelDeactivation
|
||||
Future<ActorRef> deactivationFuture =
|
||||
camel.deactivationFutureFor(producer, timeout, system.dispatcher());
|
||||
// #CamelDeactivation
|
||||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +52,6 @@ public class ActivationTestBase extends AbstractJavaTest {
|
|||
return "direct:test";
|
||||
}
|
||||
|
||||
public void onReceive(Object message) {
|
||||
}
|
||||
public void onReceive(Object message) {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,23 +16,23 @@ import org.junit.Test;
|
|||
public class CamelExtensionTest extends AbstractJavaTest {
|
||||
@Test
|
||||
public void getCamelExtension() {
|
||||
//#CamelExtension
|
||||
// #CamelExtension
|
||||
ActorSystem system = ActorSystem.create("some-system");
|
||||
Camel camel = CamelExtension.get(system);
|
||||
CamelContext camelContext = camel.context();
|
||||
ProducerTemplate producerTemplate = camel.template();
|
||||
//#CamelExtension
|
||||
// #CamelExtension
|
||||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
||||
public void addActiveMQComponent() {
|
||||
//#CamelExtensionAddComponent
|
||||
// #CamelExtensionAddComponent
|
||||
ActorSystem system = ActorSystem.create("some-system");
|
||||
Camel camel = CamelExtension.get(system);
|
||||
CamelContext camelContext = camel.context();
|
||||
// camelContext.addComponent("activemq", ActiveMQComponent.activeMQComponent(
|
||||
// "vm://localhost?broker.persistent=false"));
|
||||
//#CamelExtensionAddComponent
|
||||
// #CamelExtensionAddComponent
|
||||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#Consumer1
|
||||
// #Consumer1
|
||||
import akka.camel.CamelMessage;
|
||||
import akka.camel.javaapi.UntypedConsumerActor;
|
||||
import akka.event.Logging;
|
||||
|
|
@ -21,8 +21,7 @@ public class Consumer1 extends UntypedConsumerActor {
|
|||
CamelMessage camelMessage = (CamelMessage) message;
|
||||
String body = camelMessage.getBodyAs(String.class, getCamelContext());
|
||||
log.info("Received message: {}", body);
|
||||
} else
|
||||
unhandled(message);
|
||||
} else unhandled(message);
|
||||
}
|
||||
}
|
||||
//#Consumer1
|
||||
// #Consumer1
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#Consumer2
|
||||
// #Consumer2
|
||||
import akka.camel.CamelMessage;
|
||||
import akka.camel.javaapi.UntypedConsumerActor;
|
||||
|
||||
|
|
@ -16,9 +16,8 @@ public class Consumer2 extends UntypedConsumerActor {
|
|||
if (message instanceof CamelMessage) {
|
||||
CamelMessage camelMessage = (CamelMessage) message;
|
||||
String body = camelMessage.getBodyAs(String.class, getCamelContext());
|
||||
getSender().tell(String.format("Received message: %s",body), getSelf());
|
||||
} else
|
||||
unhandled(message);
|
||||
getSender().tell(String.format("Received message: %s", body), getSelf());
|
||||
} else unhandled(message);
|
||||
}
|
||||
}
|
||||
//#Consumer2
|
||||
// #Consumer2
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#Consumer3
|
||||
// #Consumer3
|
||||
import akka.actor.Status;
|
||||
import akka.camel.Ack;
|
||||
import akka.camel.CamelMessage;
|
||||
import akka.camel.javaapi.UntypedConsumerActor;
|
||||
|
||||
public class Consumer3 extends UntypedConsumerActor{
|
||||
public class Consumer3 extends UntypedConsumerActor {
|
||||
|
||||
@Override
|
||||
public boolean autoAck() {
|
||||
|
|
@ -28,8 +28,7 @@ public class Consumer3 extends UntypedConsumerActor{
|
|||
Exception someException = new Exception("e1");
|
||||
// on failure
|
||||
getSender().tell(new Status.Failure(someException), getSelf());
|
||||
} else
|
||||
unhandled(message);
|
||||
} else unhandled(message);
|
||||
}
|
||||
}
|
||||
//#Consumer3
|
||||
// #Consumer3
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#Consumer4
|
||||
// #Consumer4
|
||||
import akka.camel.CamelMessage;
|
||||
import akka.camel.javaapi.UntypedConsumerActor;
|
||||
import scala.concurrent.duration.Duration;
|
||||
|
|
@ -12,8 +12,7 @@ import scala.concurrent.duration.FiniteDuration;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Consumer4 extends UntypedConsumerActor {
|
||||
private final static FiniteDuration timeout =
|
||||
Duration.create(500, TimeUnit.MILLISECONDS);
|
||||
private static final FiniteDuration timeout = Duration.create(500, TimeUnit.MILLISECONDS);
|
||||
|
||||
@Override
|
||||
public FiniteDuration replyTimeout() {
|
||||
|
|
@ -28,9 +27,8 @@ public class Consumer4 extends UntypedConsumerActor {
|
|||
if (message instanceof CamelMessage) {
|
||||
CamelMessage camelMessage = (CamelMessage) message;
|
||||
String body = camelMessage.getBodyAs(String.class, getCamelContext());
|
||||
getSender().tell(String.format("Hello %s",body), getSelf());
|
||||
} else
|
||||
unhandled(message);
|
||||
getSender().tell(String.format("Hello %s", body), getSelf());
|
||||
} else unhandled(message);
|
||||
}
|
||||
}
|
||||
//#Consumer4
|
||||
// #Consumer4
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#CustomRoute
|
||||
// #CustomRoute
|
||||
import akka.actor.ActorRef;
|
||||
import akka.camel.internal.component.CamelPath;
|
||||
import org.apache.camel.builder.RouteBuilder;
|
||||
|
||||
public class CustomRouteBuilder extends RouteBuilder{
|
||||
public class CustomRouteBuilder extends RouteBuilder {
|
||||
private String uri;
|
||||
|
||||
public CustomRouteBuilder(ActorRef responder) {
|
||||
|
|
@ -19,4 +19,4 @@ public class CustomRouteBuilder extends RouteBuilder{
|
|||
from("jetty:http://localhost:8877/camel/custom").to(uri);
|
||||
}
|
||||
}
|
||||
//#CustomRoute
|
||||
// #CustomRoute
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@ import akka.camel.CamelExtension;
|
|||
import akka.testkit.javadsl.TestKit;
|
||||
|
||||
public class CustomRouteTestBase {
|
||||
public void customRoute() throws Exception{
|
||||
//#CustomRoute
|
||||
public void customRoute() throws Exception {
|
||||
// #CustomRoute
|
||||
ActorSystem system = ActorSystem.create("some-system");
|
||||
try {
|
||||
Camel camel = CamelExtension.get(system);
|
||||
ActorRef responder = system.actorOf(Props.create(Responder.class), "TestResponder");
|
||||
camel.context().addRoutes(new CustomRouteBuilder(responder));
|
||||
//#CustomRoute
|
||||
// #CustomRoute
|
||||
} finally {
|
||||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#ErrorThrowingConsumer
|
||||
// #ErrorThrowingConsumer
|
||||
import akka.actor.Status;
|
||||
import akka.camel.CamelMessage;
|
||||
import akka.camel.javaapi.UntypedConsumerActor;
|
||||
|
|
@ -13,20 +13,22 @@ import org.apache.camel.model.ProcessorDefinition;
|
|||
import org.apache.camel.model.RouteDefinition;
|
||||
import scala.Option;
|
||||
|
||||
public class ErrorThrowingConsumer extends UntypedConsumerActor{
|
||||
public class ErrorThrowingConsumer extends UntypedConsumerActor {
|
||||
private String uri;
|
||||
|
||||
private static Mapper<RouteDefinition, ProcessorDefinition<?>> mapper =
|
||||
new Mapper<RouteDefinition, ProcessorDefinition<?>>() {
|
||||
public ProcessorDefinition<?> apply(RouteDefinition rd) {
|
||||
// Catch any exception and handle it by returning the exception message
|
||||
// as response
|
||||
return rd.onException(Exception.class).handled(true).
|
||||
transform(Builder.exceptionMessage()).end();
|
||||
}
|
||||
};
|
||||
new Mapper<RouteDefinition, ProcessorDefinition<?>>() {
|
||||
public ProcessorDefinition<?> apply(RouteDefinition rd) {
|
||||
// Catch any exception and handle it by returning the exception message
|
||||
// as response
|
||||
return rd.onException(Exception.class)
|
||||
.handled(true)
|
||||
.transform(Builder.exceptionMessage())
|
||||
.end();
|
||||
}
|
||||
};
|
||||
|
||||
public ErrorThrowingConsumer(String uri){
|
||||
public ErrorThrowingConsumer(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
|
|
@ -34,18 +36,16 @@ public class ErrorThrowingConsumer extends UntypedConsumerActor{
|
|||
return uri;
|
||||
}
|
||||
|
||||
public void onReceive(Object message) throws Exception{
|
||||
public void onReceive(Object message) throws Exception {
|
||||
if (message instanceof CamelMessage) {
|
||||
CamelMessage camelMessage = (CamelMessage) message;
|
||||
String body = camelMessage.getBodyAs(String.class, getCamelContext());
|
||||
throw new Exception(String.format("error: %s",body));
|
||||
} else
|
||||
unhandled(message);
|
||||
throw new Exception(String.format("error: %s", body));
|
||||
} else unhandled(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mapper<RouteDefinition,
|
||||
ProcessorDefinition<?>> getRouteDefinitionHandler() {
|
||||
public Mapper<RouteDefinition, ProcessorDefinition<?>> getRouteDefinitionHandler() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
|
|
@ -54,4 +54,4 @@ public class ErrorThrowingConsumer extends UntypedConsumerActor{
|
|||
getSender().tell(new Status.Failure(reason), getSelf());
|
||||
}
|
||||
}
|
||||
//#ErrorThrowingConsumer
|
||||
// #ErrorThrowingConsumer
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@
|
|||
|
||||
package jdocs.camel;
|
||||
|
||||
//#Producer1
|
||||
// #Producer1
|
||||
import akka.camel.javaapi.UntypedProducerActor;
|
||||
|
||||
public class FirstProducer extends UntypedProducerActor {
|
||||
public String getEndpointUri() {
|
||||
return "http://localhost:8080/news";
|
||||
}
|
||||
}
|
||||
//#Producer1
|
||||
// #Producer1
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#RouteResponse
|
||||
// #RouteResponse
|
||||
import akka.actor.ActorRef;
|
||||
import akka.camel.javaapi.UntypedProducerActor;
|
||||
|
||||
|
|
@ -25,4 +25,4 @@ public class Forwarder extends UntypedProducerActor {
|
|||
target.forward(message, getContext());
|
||||
}
|
||||
}
|
||||
//#RouteResponse
|
||||
// #RouteResponse
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#ProducerTemplate
|
||||
// #ProducerTemplate
|
||||
import akka.actor.UntypedAbstractActor;
|
||||
import akka.camel.Camel;
|
||||
import akka.camel.CamelExtension;
|
||||
|
|
@ -16,4 +16,4 @@ public class MyActor extends UntypedAbstractActor {
|
|||
template.sendBody("direct:news", message);
|
||||
}
|
||||
}
|
||||
//#ProducerTemplate
|
||||
// #ProducerTemplate
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
|
||||
package jdocs.camel;
|
||||
|
||||
//#Consumer-mina
|
||||
// #Consumer-mina
|
||||
import akka.camel.CamelMessage;
|
||||
import akka.camel.javaapi.UntypedConsumerActor;
|
||||
|
||||
public class MyEndpoint extends UntypedConsumerActor{
|
||||
public class MyEndpoint extends UntypedConsumerActor {
|
||||
private String uri;
|
||||
|
||||
public String getEndpointUri() {
|
||||
|
|
@ -18,8 +18,7 @@ public class MyEndpoint extends UntypedConsumerActor{
|
|||
public void onReceive(Object message) throws Exception {
|
||||
if (message instanceof CamelMessage) {
|
||||
/* ... */
|
||||
} else
|
||||
unhandled(message);
|
||||
} else unhandled(message);
|
||||
}
|
||||
|
||||
// Extra constructor to change the default uri,
|
||||
|
|
@ -32,4 +31,4 @@ public class MyEndpoint extends UntypedConsumerActor{
|
|||
this.uri = "mina2:tcp://localhost:6200?textline=true";
|
||||
}
|
||||
}
|
||||
//#Consumer-mina
|
||||
// #Consumer-mina
|
||||
|
|
|
|||
|
|
@ -9,17 +9,17 @@ import akka.testkit.javadsl.TestKit;
|
|||
|
||||
public class OnRouteResponseTestBase {
|
||||
|
||||
public void onRouteResponse(){
|
||||
//#RouteResponse
|
||||
public void onRouteResponse() {
|
||||
// #RouteResponse
|
||||
ActorSystem system = ActorSystem.create("some-system");
|
||||
Props receiverProps = Props.create(ResponseReceiver.class);
|
||||
final ActorRef receiver = system.actorOf(receiverProps,"responseReceiver");
|
||||
ActorRef forwardResponse = system.actorOf(Props.create(
|
||||
Forwarder.class, "http://localhost:8080/news/akka", receiver));
|
||||
final ActorRef receiver = system.actorOf(receiverProps, "responseReceiver");
|
||||
ActorRef forwardResponse =
|
||||
system.actorOf(Props.create(Forwarder.class, "http://localhost:8080/news/akka", receiver));
|
||||
// the Forwarder sends out a request to the web page and forwards the response to
|
||||
// the ResponseReceiver
|
||||
forwardResponse.tell("some request", ActorRef.noSender());
|
||||
//#RouteResponse
|
||||
// #RouteResponse
|
||||
system.stop(receiver);
|
||||
system.stop(forwardResponse);
|
||||
TestKit.shutdownActorSystem(system);
|
||||
|
|
|
|||
|
|
@ -3,15 +3,16 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#Oneway
|
||||
// #Oneway
|
||||
import akka.camel.javaapi.UntypedProducerActor;
|
||||
|
||||
public class OnewaySender extends UntypedProducerActor{
|
||||
public class OnewaySender extends UntypedProducerActor {
|
||||
private String uri;
|
||||
|
||||
public OnewaySender(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public String getEndpointUri() {
|
||||
return uri;
|
||||
}
|
||||
|
|
@ -21,4 +22,4 @@ public class OnewaySender extends UntypedProducerActor{
|
|||
return true;
|
||||
}
|
||||
}
|
||||
//#Oneway
|
||||
// #Oneway
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#Producer
|
||||
// #Producer
|
||||
import akka.camel.javaapi.UntypedProducerActor;
|
||||
|
||||
public class Orders extends UntypedProducerActor {
|
||||
|
|
@ -11,4 +11,4 @@ public class Orders extends UntypedProducerActor {
|
|||
return "jms:queue:Orders";
|
||||
}
|
||||
}
|
||||
//#Producer
|
||||
// #Producer
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#Producer1
|
||||
// #Producer1
|
||||
import akka.camel.javaapi.UntypedProducerActor;
|
||||
|
||||
public class Producer1 extends UntypedProducerActor {
|
||||
|
|
@ -11,4 +11,4 @@ public class Producer1 extends UntypedProducerActor {
|
|||
return "http://localhost:8080/news";
|
||||
}
|
||||
}
|
||||
//#Producer1
|
||||
// #Producer1
|
||||
|
|
|
|||
|
|
@ -18,39 +18,39 @@ import akka.camel.CamelMessage;
|
|||
|
||||
public class ProducerTestBase {
|
||||
public void tellJmsProducer() {
|
||||
//#TellProducer
|
||||
// #TellProducer
|
||||
ActorSystem system = ActorSystem.create("some-system");
|
||||
Props props = Props.create(Orders.class);
|
||||
ActorRef producer = system.actorOf(props, "jmsproducer");
|
||||
producer.tell("<order amount=\"100\" currency=\"PLN\" itemId=\"12345\"/>",
|
||||
ActorRef.noSender());
|
||||
//#TellProducer
|
||||
producer.tell("<order amount=\"100\" currency=\"PLN\" itemId=\"12345\"/>", ActorRef.noSender());
|
||||
// #TellProducer
|
||||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void askProducer() {
|
||||
//#AskProducer
|
||||
// #AskProducer
|
||||
ActorSystem system = ActorSystem.create("some-system");
|
||||
Props props = Props.create(FirstProducer.class);
|
||||
ActorRef producer = system.actorOf(props,"myproducer");
|
||||
CompletionStage<Object> future = Patterns.ask(producer, "some request",
|
||||
Duration.ofMillis(1000L));
|
||||
//#AskProducer
|
||||
ActorRef producer = system.actorOf(props, "myproducer");
|
||||
CompletionStage<Object> future =
|
||||
Patterns.ask(producer, "some request", Duration.ofMillis(1000L));
|
||||
// #AskProducer
|
||||
system.stop(producer);
|
||||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
||||
public void correlate(){
|
||||
//#Correlate
|
||||
public void correlate() {
|
||||
// #Correlate
|
||||
ActorSystem system = ActorSystem.create("some-system");
|
||||
Props props = Props.create(Orders.class);
|
||||
ActorRef producer = system.actorOf(props,"jmsproducer");
|
||||
Map<String,Object> headers = new HashMap<String, Object>();
|
||||
headers.put(CamelMessage.MessageExchangeId(),"123");
|
||||
producer.tell(new CamelMessage("<order amount=\"100\" currency=\"PLN\" " +
|
||||
"itemId=\"12345\"/>",headers), ActorRef.noSender());
|
||||
//#Correlate
|
||||
ActorRef producer = system.actorOf(props, "jmsproducer");
|
||||
Map<String, Object> headers = new HashMap<String, Object>();
|
||||
headers.put(CamelMessage.MessageExchangeId(), "123");
|
||||
producer.tell(
|
||||
new CamelMessage("<order amount=\"100\" currency=\"PLN\" " + "itemId=\"12345\"/>", headers),
|
||||
ActorRef.noSender());
|
||||
// #Correlate
|
||||
system.stop(producer);
|
||||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#RequestProducerTemplate
|
||||
// #RequestProducerTemplate
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.camel.Camel;
|
||||
import akka.camel.CamelExtension;
|
||||
|
|
@ -13,12 +13,13 @@ public class RequestBodyActor extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchAny(message -> {
|
||||
Camel camel = CamelExtension.get(getContext().getSystem());
|
||||
ProducerTemplate template = camel.template();
|
||||
getSender().tell(template.requestBody("direct:news", message), getSelf());
|
||||
})
|
||||
.build();
|
||||
.matchAny(
|
||||
message -> {
|
||||
Camel camel = CamelExtension.get(getContext().getSystem());
|
||||
ProducerTemplate template = camel.template();
|
||||
getSender().tell(template.requestBody("direct:news", message), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#RequestProducerTemplate
|
||||
// #RequestProducerTemplate
|
||||
|
|
|
|||
|
|
@ -3,28 +3,28 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#CustomRoute
|
||||
// #CustomRoute
|
||||
import akka.actor.UntypedAbstractActor;
|
||||
import akka.camel.CamelMessage;
|
||||
import akka.dispatch.Mapper;
|
||||
|
||||
public class Responder extends UntypedAbstractActor{
|
||||
public class Responder extends UntypedAbstractActor {
|
||||
|
||||
public void onReceive(Object message) {
|
||||
if (message instanceof CamelMessage) {
|
||||
CamelMessage camelMessage = (CamelMessage) message;
|
||||
getSender().tell(createResponse(camelMessage), getSelf());
|
||||
} else
|
||||
unhandled(message);
|
||||
} else unhandled(message);
|
||||
}
|
||||
|
||||
private CamelMessage createResponse(CamelMessage msg) {
|
||||
return msg.mapBody(new Mapper<String,String>() {
|
||||
@Override
|
||||
public String apply(String body) {
|
||||
return String.format("received %s", body);
|
||||
}
|
||||
});
|
||||
return msg.mapBody(
|
||||
new Mapper<String, String>() {
|
||||
@Override
|
||||
public String apply(String body) {
|
||||
return String.format("received %s", body);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
//#CustomRoute
|
||||
// #CustomRoute
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#RouteResponse
|
||||
// #RouteResponse
|
||||
import akka.actor.UntypedAbstractActor;
|
||||
import akka.camel.CamelMessage;
|
||||
|
||||
public class ResponseReceiver extends UntypedAbstractActor{
|
||||
public class ResponseReceiver extends UntypedAbstractActor {
|
||||
public void onReceive(Object message) {
|
||||
if(message instanceof CamelMessage) {
|
||||
// do something with the forwarded response
|
||||
}
|
||||
if (message instanceof CamelMessage) {
|
||||
// do something with the forwarded response
|
||||
}
|
||||
}
|
||||
}
|
||||
//#RouteResponse
|
||||
// #RouteResponse
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
*/
|
||||
|
||||
package jdocs.camel;
|
||||
//#TransformOutgoingMessage
|
||||
// #TransformOutgoingMessage
|
||||
import akka.camel.CamelMessage;
|
||||
import akka.camel.javaapi.UntypedProducerActor;
|
||||
import akka.dispatch.Mapper;
|
||||
|
||||
public class Transformer extends UntypedProducerActor{
|
||||
public class Transformer extends UntypedProducerActor {
|
||||
private String uri;
|
||||
|
||||
public Transformer(String uri) {
|
||||
|
|
@ -20,17 +20,18 @@ public class Transformer extends UntypedProducerActor{
|
|||
}
|
||||
|
||||
private CamelMessage upperCase(CamelMessage msg) {
|
||||
return msg.mapBody(new Mapper<String,String>() {
|
||||
@Override
|
||||
public String apply(String body) {
|
||||
return body.toUpperCase();
|
||||
}
|
||||
});
|
||||
return msg.mapBody(
|
||||
new Mapper<String, String>() {
|
||||
@Override
|
||||
public String apply(String body) {
|
||||
return body.toUpperCase();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object onTransformOutgoingMessage(Object message) {
|
||||
if(message instanceof CamelMessage) {
|
||||
if (message instanceof CamelMessage) {
|
||||
CamelMessage camelMessage = (CamelMessage) message;
|
||||
return upperCase(camelMessage);
|
||||
} else {
|
||||
|
|
@ -38,4 +39,4 @@ public class Transformer extends UntypedProducerActor{
|
|||
}
|
||||
}
|
||||
}
|
||||
//#TransformOutgoingMessage
|
||||
// #TransformOutgoingMessage
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package jdocs.circuitbreaker;
|
||||
|
||||
//#imports1
|
||||
// #imports1
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.event.LoggingAdapter;
|
||||
|
|
@ -16,45 +16,55 @@ import static akka.pattern.Patterns.pipe;
|
|||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
//#imports1
|
||||
// #imports1
|
||||
|
||||
//#circuit-breaker-initialization
|
||||
// #circuit-breaker-initialization
|
||||
public class DangerousJavaActor extends AbstractActor {
|
||||
|
||||
private final CircuitBreaker breaker;
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
|
||||
public DangerousJavaActor() {
|
||||
this.breaker = new CircuitBreaker(
|
||||
getContext().getDispatcher(), getContext().getSystem().getScheduler(),
|
||||
5, Duration.ofSeconds(10), Duration.ofMinutes(1))
|
||||
.addOnOpenListener(this::notifyMeOnOpen);
|
||||
this.breaker =
|
||||
new CircuitBreaker(
|
||||
getContext().getDispatcher(),
|
||||
getContext().getSystem().getScheduler(),
|
||||
5,
|
||||
Duration.ofSeconds(10),
|
||||
Duration.ofMinutes(1))
|
||||
.addOnOpenListener(this::notifyMeOnOpen);
|
||||
}
|
||||
|
||||
public void notifyMeOnOpen() {
|
||||
log.warning("My CircuitBreaker is now open, and will not close for one minute");
|
||||
}
|
||||
//#circuit-breaker-initialization
|
||||
// #circuit-breaker-initialization
|
||||
|
||||
//#circuit-breaker-usage
|
||||
// #circuit-breaker-usage
|
||||
public String dangerousCall() {
|
||||
return "This really isn't that dangerous of a call after all";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder().
|
||||
match(String.class, "is my middle name"::equals, m -> pipe(
|
||||
breaker.callWithCircuitBreakerCS(() ->
|
||||
CompletableFuture.supplyAsync(this::dangerousCall)
|
||||
), getContext().getDispatcher()
|
||||
).to(sender()))
|
||||
.match(String.class, "block for me"::equals, m -> {
|
||||
sender().tell(breaker
|
||||
.callWithSyncCircuitBreaker(this::dangerousCall), self());
|
||||
})
|
||||
.build();
|
||||
return receiveBuilder()
|
||||
.match(
|
||||
String.class,
|
||||
"is my middle name"::equals,
|
||||
m ->
|
||||
pipe(
|
||||
breaker.callWithCircuitBreakerCS(
|
||||
() -> CompletableFuture.supplyAsync(this::dangerousCall)),
|
||||
getContext().getDispatcher())
|
||||
.to(sender()))
|
||||
.match(
|
||||
String.class,
|
||||
"block for me"::equals,
|
||||
m -> {
|
||||
sender().tell(breaker.callWithSyncCircuitBreaker(this::dangerousCall), self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
//#circuit-breaker-usage
|
||||
// #circuit-breaker-usage
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,26 +12,30 @@ import java.util.Optional;
|
|||
import java.util.function.BiFunction;
|
||||
|
||||
public class EvenNoFailureJavaExample extends AbstractActor {
|
||||
//#even-no-as-failure
|
||||
private final CircuitBreaker breaker;
|
||||
// #even-no-as-failure
|
||||
private final CircuitBreaker breaker;
|
||||
|
||||
public EvenNoFailureJavaExample() {
|
||||
this.breaker = new CircuitBreaker(
|
||||
getContext().getDispatcher(), getContext().getSystem().getScheduler(),
|
||||
5, Duration.ofSeconds(10), Duration.ofMinutes(1));
|
||||
}
|
||||
public EvenNoFailureJavaExample() {
|
||||
this.breaker =
|
||||
new CircuitBreaker(
|
||||
getContext().getDispatcher(),
|
||||
getContext().getSystem().getScheduler(),
|
||||
5,
|
||||
Duration.ofSeconds(10),
|
||||
Duration.ofMinutes(1));
|
||||
}
|
||||
|
||||
public int luckyNumber() {
|
||||
BiFunction<Optional<Integer>, Optional<Throwable>, Boolean> evenNoAsFailure =
|
||||
(result, err) -> (result.isPresent() && result.get() % 2 == 0);
|
||||
public int luckyNumber() {
|
||||
BiFunction<Optional<Integer>, Optional<Throwable>, Boolean> evenNoAsFailure =
|
||||
(result, err) -> (result.isPresent() && result.get() % 2 == 0);
|
||||
|
||||
// this will return 8888 and increase failure count at the same time
|
||||
return this.breaker.callWithSyncCircuitBreaker(() -> 8888, evenNoAsFailure);
|
||||
}
|
||||
// this will return 8888 and increase failure count at the same time
|
||||
return this.breaker.callWithSyncCircuitBreaker(() -> 8888, evenNoAsFailure);
|
||||
}
|
||||
|
||||
//#even-no-as-failure
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return null;
|
||||
}
|
||||
// #even-no-as-failure
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,40 +14,39 @@ import java.time.Duration;
|
|||
|
||||
public class TellPatternJavaActor extends AbstractActor {
|
||||
|
||||
private final ActorRef target;
|
||||
private final ActorRef target;
|
||||
private final CircuitBreaker breaker;
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
|
||||
public TellPatternJavaActor(ActorRef targetActor) {
|
||||
this.target = targetActor;
|
||||
this.breaker = new CircuitBreaker(
|
||||
getContext().getDispatcher(), getContext().getSystem().getScheduler(),
|
||||
5, Duration.ofSeconds(10), Duration.ofMinutes(1))
|
||||
.addOnOpenListener(this::notifyMeOnOpen);
|
||||
this.target = targetActor;
|
||||
this.breaker =
|
||||
new CircuitBreaker(
|
||||
getContext().getDispatcher(),
|
||||
getContext().getSystem().getScheduler(),
|
||||
5,
|
||||
Duration.ofSeconds(10),
|
||||
Duration.ofMinutes(1))
|
||||
.addOnOpenListener(this::notifyMeOnOpen);
|
||||
}
|
||||
|
||||
public void notifyMeOnOpen() {
|
||||
log.warning("My CircuitBreaker is now open, and will not close for one minute");
|
||||
}
|
||||
|
||||
//#circuit-breaker-tell-pattern
|
||||
// #circuit-breaker-tell-pattern
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(String.class, payload -> "call".equals(payload) && breaker.isClosed(), payload ->
|
||||
target.tell("message", self())
|
||||
)
|
||||
.matchEquals("response", payload ->
|
||||
breaker.succeed()
|
||||
)
|
||||
.match(Throwable.class, t ->
|
||||
breaker.fail()
|
||||
)
|
||||
.match(ReceiveTimeout.class, t ->
|
||||
breaker.fail()
|
||||
)
|
||||
.build();
|
||||
.match(
|
||||
String.class,
|
||||
payload -> "call".equals(payload) && breaker.isClosed(),
|
||||
payload -> target.tell("message", self()))
|
||||
.matchEquals("response", payload -> breaker.succeed())
|
||||
.match(Throwable.class, t -> breaker.fail())
|
||||
.match(ReceiveTimeout.class, t -> breaker.fail())
|
||||
.build();
|
||||
}
|
||||
//#circuit-breaker-tell-pattern
|
||||
// #circuit-breaker-tell-pattern
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,23 +15,24 @@ import org.junit.AfterClass;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
//#join-seed-nodes-imports
|
||||
// #join-seed-nodes-imports
|
||||
import akka.actor.Address;
|
||||
import akka.cluster.Cluster;
|
||||
|
||||
//#join-seed-nodes-imports
|
||||
// #join-seed-nodes-imports
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.cluster.Member;
|
||||
|
||||
|
||||
public class ClusterDocTest extends AbstractJavaTest {
|
||||
|
||||
|
||||
static ActorSystem system;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
system = ActorSystem.create("ClusterDocTest",
|
||||
ConfigFactory.parseString(scala.docs.cluster.ClusterDocSpec.config()));
|
||||
system =
|
||||
ActorSystem.create(
|
||||
"ClusterDocTest",
|
||||
ConfigFactory.parseString(scala.docs.cluster.ClusterDocSpec.config()));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
|
@ -42,17 +43,17 @@ public class ClusterDocTest extends AbstractJavaTest {
|
|||
|
||||
@Test
|
||||
public void demonstrateLeave() {
|
||||
//#leave
|
||||
// #leave
|
||||
final Cluster cluster = Cluster.get(system);
|
||||
cluster.leave(cluster.selfAddress());
|
||||
//#leave
|
||||
// #leave
|
||||
|
||||
}
|
||||
|
||||
// compile only
|
||||
|
||||
// compile only
|
||||
@SuppressWarnings("unused")
|
||||
public void demonstrateDataCenter() {
|
||||
//#dcAccess
|
||||
// #dcAccess
|
||||
final Cluster cluster = Cluster.get(system);
|
||||
// this node's data center
|
||||
String dc = cluster.selfDataCenter();
|
||||
|
|
@ -61,16 +62,17 @@ public class ClusterDocTest extends AbstractJavaTest {
|
|||
// a specific member's data center
|
||||
Member aMember = cluster.state().getMembers().iterator().next();
|
||||
String aDc = aMember.dataCenter();
|
||||
//#dcAccess
|
||||
// #dcAccess
|
||||
}
|
||||
|
||||
// compile only
|
||||
@SuppressWarnings("unused")
|
||||
public void demonstrateJoinSeedNodes() {
|
||||
//#join-seed-nodes
|
||||
// #join-seed-nodes
|
||||
final Cluster cluster = Cluster.get(system);
|
||||
List<Address> list = new LinkedList<>(); //replace this with your method to dynamically get seed nodes
|
||||
List<Address> list =
|
||||
new LinkedList<>(); // replace this with your method to dynamically get seed nodes
|
||||
cluster.joinSeedNodes(list);
|
||||
//#join-seed-nodes
|
||||
// #join-seed-nodes
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,22 +10,22 @@ import java.util.concurrent.CompletableFuture;
|
|||
import akka.actor.AbstractActor;
|
||||
import static akka.pattern.Patterns.pipe;
|
||||
|
||||
//#backend
|
||||
// #backend
|
||||
public class FactorialBackend extends AbstractActor {
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Integer.class, n -> {
|
||||
.match(
|
||||
Integer.class,
|
||||
n -> {
|
||||
CompletableFuture<FactorialResult> result =
|
||||
CompletableFuture.supplyAsync(() -> factorial(n))
|
||||
.thenApply((factorial) -> new FactorialResult(n, factorial));
|
||||
|
||||
CompletableFuture<FactorialResult> result =
|
||||
CompletableFuture.supplyAsync(() -> factorial(n))
|
||||
.thenApply((factorial) -> new FactorialResult(n, factorial));
|
||||
|
||||
pipe(result, getContext().dispatcher()).to(getSender());
|
||||
|
||||
})
|
||||
.build();
|
||||
pipe(result, getContext().dispatcher()).to(getSender());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
BigInteger factorial(int n) {
|
||||
|
|
@ -36,5 +36,4 @@ public class FactorialBackend extends AbstractActor {
|
|||
return acc;
|
||||
}
|
||||
}
|
||||
//#backend
|
||||
|
||||
// #backend
|
||||
|
|
|
|||
|
|
@ -26,15 +26,15 @@ import akka.event.Logging;
|
|||
import akka.event.LoggingAdapter;
|
||||
import akka.routing.FromConfig;
|
||||
|
||||
//#frontend
|
||||
// #frontend
|
||||
public class FactorialFrontend extends AbstractActor {
|
||||
final int upToN;
|
||||
final boolean repeat;
|
||||
|
||||
LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
ActorRef backend = getContext().actorOf(FromConfig.getInstance().props(),
|
||||
"factorialBackendRouter");
|
||||
ActorRef backend =
|
||||
getContext().actorOf(FromConfig.getInstance().props(), "factorialBackendRouter");
|
||||
|
||||
public FactorialFrontend(int upToN, boolean repeat) {
|
||||
this.upToN = upToN;
|
||||
|
|
@ -50,20 +50,22 @@ public class FactorialFrontend extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(FactorialResult.class, result -> {
|
||||
if (result.n == upToN) {
|
||||
log.debug("{}! = {}", result.n, result.factorial);
|
||||
if (repeat)
|
||||
sendJobs();
|
||||
else
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
})
|
||||
.match(ReceiveTimeout.class, x -> {
|
||||
log.info("Timeout");
|
||||
sendJobs();
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
FactorialResult.class,
|
||||
result -> {
|
||||
if (result.n == upToN) {
|
||||
log.debug("{}! = {}", result.n, result.factorial);
|
||||
if (repeat) sendJobs();
|
||||
else getContext().stop(getSelf());
|
||||
}
|
||||
})
|
||||
.match(
|
||||
ReceiveTimeout.class,
|
||||
x -> {
|
||||
log.info("Timeout");
|
||||
sendJobs();
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
void sendJobs() {
|
||||
|
|
@ -72,38 +74,46 @@ public class FactorialFrontend extends AbstractActor {
|
|||
backend.tell(n, getSelf());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//#frontend
|
||||
// #frontend
|
||||
|
||||
//not used, only for documentation
|
||||
// not used, only for documentation
|
||||
abstract class FactorialFrontend2 extends AbstractActor {
|
||||
//#router-lookup-in-code
|
||||
// #router-lookup-in-code
|
||||
int totalInstances = 100;
|
||||
Iterable<String> routeesPaths = Arrays.asList("/user/factorialBackend", "");
|
||||
boolean allowLocalRoutees = true;
|
||||
Set<String> useRoles = new HashSet<>(Arrays.asList("backend"));
|
||||
ActorRef backend = getContext().actorOf(
|
||||
new ClusterRouterGroup(new AdaptiveLoadBalancingGroup(
|
||||
HeapMetricsSelector.getInstance(), Collections.<String> emptyList()),
|
||||
new ClusterRouterGroupSettings(totalInstances, routeesPaths,
|
||||
allowLocalRoutees, useRoles)).props(), "factorialBackendRouter2");
|
||||
ActorRef backend =
|
||||
getContext()
|
||||
.actorOf(
|
||||
new ClusterRouterGroup(
|
||||
new AdaptiveLoadBalancingGroup(
|
||||
HeapMetricsSelector.getInstance(), Collections.<String>emptyList()),
|
||||
new ClusterRouterGroupSettings(
|
||||
totalInstances, routeesPaths, allowLocalRoutees, useRoles))
|
||||
.props(),
|
||||
"factorialBackendRouter2");
|
||||
|
||||
//#router-lookup-in-code
|
||||
// #router-lookup-in-code
|
||||
}
|
||||
|
||||
//not used, only for documentation
|
||||
// not used, only for documentation
|
||||
abstract class FactorialFrontend3 extends AbstractActor {
|
||||
//#router-deploy-in-code
|
||||
// #router-deploy-in-code
|
||||
int totalInstances = 100;
|
||||
int maxInstancesPerNode = 3;
|
||||
boolean allowLocalRoutees = false;
|
||||
Set<String> useRoles = new HashSet<>(Arrays.asList("backend"));
|
||||
ActorRef backend = getContext().actorOf(
|
||||
new ClusterRouterPool(new AdaptiveLoadBalancingPool(
|
||||
SystemLoadAverageMetricsSelector.getInstance(), 0),
|
||||
new ClusterRouterPoolSettings(totalInstances, maxInstancesPerNode,
|
||||
allowLocalRoutees, useRoles)).props(Props
|
||||
.create(FactorialBackend.class)), "factorialBackendRouter3");
|
||||
//#router-deploy-in-code
|
||||
ActorRef backend =
|
||||
getContext()
|
||||
.actorOf(
|
||||
new ClusterRouterPool(
|
||||
new AdaptiveLoadBalancingPool(
|
||||
SystemLoadAverageMetricsSelector.getInstance(), 0),
|
||||
new ClusterRouterPoolSettings(
|
||||
totalInstances, maxInstancesPerNode, allowLocalRoutees, useRoles))
|
||||
.props(Props.create(FactorialBackend.class)),
|
||||
"factorialBackendRouter3");
|
||||
// #router-deploy-in-code
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,56 +19,60 @@ public class FactorialFrontendMain {
|
|||
public static void main(String[] args) {
|
||||
final int upToN = 200;
|
||||
|
||||
final Config config = ConfigFactory.parseString(
|
||||
"akka.cluster.roles = [frontend]").withFallback(
|
||||
ConfigFactory.load("factorial"));
|
||||
final Config config =
|
||||
ConfigFactory.parseString("akka.cluster.roles = [frontend]")
|
||||
.withFallback(ConfigFactory.load("factorial"));
|
||||
|
||||
final ActorSystem system = ActorSystem.create("ClusterSystem", config);
|
||||
system.log().info(
|
||||
"Factorials will start when 2 backend members in the cluster.");
|
||||
//#registerOnUp
|
||||
Cluster.get(system).registerOnMemberUp(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
system.actorOf(Props.create(FactorialFrontend.class, upToN, true),
|
||||
"factorialFrontend");
|
||||
}
|
||||
});
|
||||
//#registerOnUp
|
||||
system.log().info("Factorials will start when 2 backend members in the cluster.");
|
||||
// #registerOnUp
|
||||
Cluster.get(system)
|
||||
.registerOnMemberUp(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
system.actorOf(
|
||||
Props.create(FactorialFrontend.class, upToN, true), "factorialFrontend");
|
||||
}
|
||||
});
|
||||
// #registerOnUp
|
||||
|
||||
//#registerOnRemoved
|
||||
Cluster.get(system).registerOnMemberRemoved(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// exit JVM when ActorSystem has been terminated
|
||||
final Runnable exit = new Runnable() {
|
||||
@Override public void run() {
|
||||
System.exit(0);
|
||||
}
|
||||
};
|
||||
system.registerOnTermination(exit);
|
||||
// #registerOnRemoved
|
||||
Cluster.get(system)
|
||||
.registerOnMemberRemoved(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// exit JVM when ActorSystem has been terminated
|
||||
final Runnable exit =
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
System.exit(0);
|
||||
}
|
||||
};
|
||||
system.registerOnTermination(exit);
|
||||
|
||||
// shut down ActorSystem
|
||||
system.terminate();
|
||||
// shut down ActorSystem
|
||||
system.terminate();
|
||||
|
||||
// In case ActorSystem shutdown takes longer than 10 seconds,
|
||||
// exit the JVM forcefully anyway.
|
||||
// We must spawn a separate thread to not block current thread,
|
||||
// since that would have blocked the shutdown of the ActorSystem.
|
||||
new Thread() {
|
||||
@Override public void run(){
|
||||
try {
|
||||
system.getWhenTerminated().toCompletableFuture().get(10, TimeUnit.SECONDS);
|
||||
} catch (Exception e) {
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
});
|
||||
//#registerOnRemoved
|
||||
// In case ActorSystem shutdown takes longer than 10 seconds,
|
||||
// exit the JVM forcefully anyway.
|
||||
// We must spawn a separate thread to not block current thread,
|
||||
// since that would have blocked the shutdown of the ActorSystem.
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
system.getWhenTerminated().toCompletableFuture().get(10, TimeUnit.SECONDS);
|
||||
} catch (Exception e) {
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
});
|
||||
// #registerOnRemoved
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ import java.math.BigInteger;
|
|||
import java.io.Serializable;
|
||||
|
||||
public class FactorialResult implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public final int n;
|
||||
public final BigInteger factorial;
|
||||
private static final long serialVersionUID = 1L;
|
||||
public final int n;
|
||||
public final BigInteger factorial;
|
||||
|
||||
FactorialResult(int n, BigInteger factorial) {
|
||||
this.n = n;
|
||||
this.factorial = factorial;
|
||||
}
|
||||
FactorialResult(int n, BigInteger factorial) {
|
||||
this.n = n;
|
||||
this.factorial = factorial;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package jdocs.cluster;
|
||||
|
||||
//#metrics-listener
|
||||
// #metrics-listener
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.cluster.Cluster;
|
||||
import akka.cluster.ClusterEvent.CurrentClusterState;
|
||||
|
|
@ -21,37 +21,40 @@ public class MetricsListener extends AbstractActor {
|
|||
LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
Cluster cluster = Cluster.get(getContext().getSystem());
|
||||
|
||||
|
||||
ClusterMetricsExtension extension = ClusterMetricsExtension.get(getContext().getSystem());
|
||||
|
||||
|
||||
// Subscribe unto ClusterMetricsEvent events.
|
||||
@Override
|
||||
public void preStart() {
|
||||
extension.subscribe(getSelf());
|
||||
extension.subscribe(getSelf());
|
||||
}
|
||||
|
||||
// Unsubscribe from ClusterMetricsEvent events.
|
||||
@Override
|
||||
public void postStop() {
|
||||
extension.unsubscribe(getSelf());
|
||||
extension.unsubscribe(getSelf());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(ClusterMetricsChanged.class, clusterMetrics -> {
|
||||
for (NodeMetrics nodeMetrics : clusterMetrics.getNodeMetrics()) {
|
||||
if (nodeMetrics.address().equals(cluster.selfAddress())) {
|
||||
logHeap(nodeMetrics);
|
||||
logCpu(nodeMetrics);
|
||||
}
|
||||
}
|
||||
})
|
||||
.match(CurrentClusterState.class, message -> {
|
||||
// Ignore.
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
ClusterMetricsChanged.class,
|
||||
clusterMetrics -> {
|
||||
for (NodeMetrics nodeMetrics : clusterMetrics.getNodeMetrics()) {
|
||||
if (nodeMetrics.address().equals(cluster.selfAddress())) {
|
||||
logHeap(nodeMetrics);
|
||||
logCpu(nodeMetrics);
|
||||
}
|
||||
}
|
||||
})
|
||||
.match(
|
||||
CurrentClusterState.class,
|
||||
message -> {
|
||||
// Ignore.
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
void logHeap(NodeMetrics nodeMetrics) {
|
||||
|
|
@ -64,10 +67,8 @@ public class MetricsListener extends AbstractActor {
|
|||
void logCpu(NodeMetrics nodeMetrics) {
|
||||
Cpu cpu = StandardMetrics.extractCpu(nodeMetrics);
|
||||
if (cpu != null && cpu.systemLoadAverage().isDefined()) {
|
||||
log.info("Load: {} ({} processors)", cpu.systemLoadAverage().get(),
|
||||
cpu.processors());
|
||||
log.info("Load: {} ({} processors)", cpu.systemLoadAverage().get(), cpu.processors());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//#metrics-listener
|
||||
// #metrics-listener
|
||||
|
|
|
|||
|
|
@ -18,16 +18,16 @@ public class SimpleClusterListener extends AbstractActor {
|
|||
LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
Cluster cluster = Cluster.get(getContext().getSystem());
|
||||
|
||||
//subscribe to cluster changes
|
||||
// subscribe to cluster changes
|
||||
@Override
|
||||
public void preStart() {
|
||||
//#subscribe
|
||||
cluster.subscribe(getSelf(), ClusterEvent.initialStateAsEvents(),
|
||||
MemberEvent.class, UnreachableMember.class);
|
||||
//#subscribe
|
||||
// #subscribe
|
||||
cluster.subscribe(
|
||||
getSelf(), ClusterEvent.initialStateAsEvents(), MemberEvent.class, UnreachableMember.class);
|
||||
// #subscribe
|
||||
}
|
||||
|
||||
//re-subscribe when restart
|
||||
// re-subscribe when restart
|
||||
@Override
|
||||
public void postStop() {
|
||||
cluster.unsubscribe(getSelf());
|
||||
|
|
@ -36,18 +36,26 @@ public class SimpleClusterListener extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(MemberUp.class, mUp -> {
|
||||
log.info("Member is Up: {}", mUp.member());
|
||||
})
|
||||
.match(UnreachableMember.class, mUnreachable -> {
|
||||
log.info("Member detected as unreachable: {}", mUnreachable.member());
|
||||
})
|
||||
.match(MemberRemoved.class, mRemoved -> {
|
||||
log.info("Member is Removed: {}", mRemoved.member());
|
||||
})
|
||||
.match(MemberEvent.class, message -> {
|
||||
// ignore
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
MemberUp.class,
|
||||
mUp -> {
|
||||
log.info("Member is Up: {}", mUp.member());
|
||||
})
|
||||
.match(
|
||||
UnreachableMember.class,
|
||||
mUnreachable -> {
|
||||
log.info("Member detected as unreachable: {}", mUnreachable.member());
|
||||
})
|
||||
.match(
|
||||
MemberRemoved.class,
|
||||
mRemoved -> {
|
||||
log.info("Member is Removed: {}", mRemoved.member());
|
||||
})
|
||||
.match(
|
||||
MemberEvent.class,
|
||||
message -> {
|
||||
// ignore
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,29 +16,28 @@ import akka.event.LoggingAdapter;
|
|||
|
||||
public class SimpleClusterListener2 extends AbstractActor {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
//#join
|
||||
// #join
|
||||
Cluster cluster = Cluster.get(getContext().getSystem());
|
||||
//#join
|
||||
// #join
|
||||
|
||||
//subscribe to cluster changes
|
||||
// subscribe to cluster changes
|
||||
@Override
|
||||
public void preStart() {
|
||||
//#join
|
||||
// #join
|
||||
cluster.join(cluster.selfAddress());
|
||||
//#join
|
||||
// #join
|
||||
|
||||
//#subscribe
|
||||
// #subscribe
|
||||
cluster.subscribe(getSelf(), MemberEvent.class, UnreachableMember.class);
|
||||
//#subscribe
|
||||
// #subscribe
|
||||
|
||||
//#register-on-memberup
|
||||
// #register-on-memberup
|
||||
cluster.registerOnMemberUp(
|
||||
() -> cluster.subscribe(getSelf(), MemberEvent.class, UnreachableMember.class)
|
||||
);
|
||||
//#register-on-memberup
|
||||
() -> cluster.subscribe(getSelf(), MemberEvent.class, UnreachableMember.class));
|
||||
// #register-on-memberup
|
||||
}
|
||||
|
||||
//re-subscribe when restart
|
||||
// re-subscribe when restart
|
||||
@Override
|
||||
public void postStop() {
|
||||
cluster.unsubscribe(getSelf());
|
||||
|
|
@ -47,21 +46,31 @@ public class SimpleClusterListener2 extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(CurrentClusterState.class, state -> {
|
||||
log.info("Current members: {}", state.members());
|
||||
})
|
||||
.match(MemberUp.class, mUp -> {
|
||||
log.info("Member is Up: {}", mUp.member());
|
||||
})
|
||||
.match(UnreachableMember.class, mUnreachable -> {
|
||||
log.info("Member detected as unreachable: {}", mUnreachable.member());
|
||||
})
|
||||
.match(MemberRemoved.class, mRemoved -> {
|
||||
log.info("Member is Removed: {}", mRemoved.member());
|
||||
})
|
||||
.match(MemberEvent.class, event -> {
|
||||
// ignore
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
CurrentClusterState.class,
|
||||
state -> {
|
||||
log.info("Current members: {}", state.members());
|
||||
})
|
||||
.match(
|
||||
MemberUp.class,
|
||||
mUp -> {
|
||||
log.info("Member is Up: {}", mUp.member());
|
||||
})
|
||||
.match(
|
||||
UnreachableMember.class,
|
||||
mUnreachable -> {
|
||||
log.info("Member detected as unreachable: {}", mUnreachable.member());
|
||||
})
|
||||
.match(
|
||||
MemberRemoved.class,
|
||||
mRemoved -> {
|
||||
log.info("Member is Removed: {}", mRemoved.member());
|
||||
})
|
||||
.match(
|
||||
MemberEvent.class,
|
||||
event -> {
|
||||
// ignore
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import akka.actor.ActorRef;
|
|||
import akka.actor.ReceiveTimeout;
|
||||
import akka.actor.AbstractActor;
|
||||
|
||||
//#aggregator
|
||||
// #aggregator
|
||||
public class StatsAggregator extends AbstractActor {
|
||||
|
||||
final int expectedResults;
|
||||
|
|
@ -34,25 +34,27 @@ public class StatsAggregator extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Integer.class, wordCount -> {
|
||||
results.add(wordCount);
|
||||
if (results.size() == expectedResults) {
|
||||
int sum = 0;
|
||||
for (int c : results) {
|
||||
sum += c;
|
||||
}
|
||||
double meanWordLength = ((double) sum) / results.size();
|
||||
replyTo.tell(new StatsResult(meanWordLength), getSelf());
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
})
|
||||
.match(ReceiveTimeout.class, x -> {
|
||||
replyTo.tell(new JobFailed("Service unavailable, try again later"),
|
||||
getSelf());
|
||||
getContext().stop(getSelf());
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
Integer.class,
|
||||
wordCount -> {
|
||||
results.add(wordCount);
|
||||
if (results.size() == expectedResults) {
|
||||
int sum = 0;
|
||||
for (int c : results) {
|
||||
sum += c;
|
||||
}
|
||||
double meanWordLength = ((double) sum) / results.size();
|
||||
replyTo.tell(new StatsResult(meanWordLength), getSelf());
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
})
|
||||
.match(
|
||||
ReceiveTimeout.class,
|
||||
x -> {
|
||||
replyTo.tell(new JobFailed("Service unavailable, try again later"), getSelf());
|
||||
getContext().stop(getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
//#aggregator
|
||||
// #aggregator
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ package jdocs.cluster;
|
|||
|
||||
import java.io.Serializable;
|
||||
|
||||
//#messages
|
||||
// #messages
|
||||
public interface StatsMessages {
|
||||
|
||||
public static class StatsJob implements Serializable {
|
||||
|
|
@ -54,6 +54,5 @@ public interface StatsMessages {
|
|||
return "JobFailed(" + reason + ")";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//#messages
|
||||
// #messages
|
||||
|
|
|
|||
|
|
@ -39,20 +39,20 @@ public class StatsSampleClient extends AbstractActor {
|
|||
public StatsSampleClient(String servicePath) {
|
||||
this.servicePath = servicePath;
|
||||
Duration interval = Duration.ofMillis(2);
|
||||
tickTask = getContext()
|
||||
.getSystem()
|
||||
.scheduler()
|
||||
.schedule(interval, interval, getSelf(), "tick",
|
||||
getContext().getDispatcher(), null);
|
||||
tickTask =
|
||||
getContext()
|
||||
.getSystem()
|
||||
.scheduler()
|
||||
.schedule(interval, interval, getSelf(), "tick", getContext().getDispatcher(), null);
|
||||
}
|
||||
|
||||
//subscribe to cluster changes, MemberEvent
|
||||
// subscribe to cluster changes, MemberEvent
|
||||
@Override
|
||||
public void preStart() {
|
||||
cluster.subscribe(getSelf(), MemberEvent.class, ReachabilityEvent.class);
|
||||
}
|
||||
|
||||
//re-subscribe when restart
|
||||
// re-subscribe when restart
|
||||
@Override
|
||||
public void postStop() {
|
||||
cluster.unsubscribe(getSelf());
|
||||
|
|
@ -62,41 +62,49 @@ public class StatsSampleClient extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("tick", x -> !nodes.isEmpty(), x -> {
|
||||
// just pick any one
|
||||
List<Address> nodesList = new ArrayList<Address>(nodes);
|
||||
Address address = nodesList.get(ThreadLocalRandom.current().nextInt(
|
||||
nodesList.size()));
|
||||
ActorSelection service = getContext().actorSelection(address + servicePath);
|
||||
service.tell(new StatsJob("this is the text that will be analyzed"),
|
||||
getSelf());
|
||||
})
|
||||
.match(StatsResult.class, System.out::println)
|
||||
.match(JobFailed.class, System.out::println)
|
||||
.match(CurrentClusterState.class, state -> {
|
||||
nodes.clear();
|
||||
for (Member member : state.getMembers()) {
|
||||
if (member.hasRole("compute") && member.status().equals(MemberStatus.up())) {
|
||||
nodes.add(member.address());
|
||||
}
|
||||
}
|
||||
})
|
||||
.match(MemberUp.class, mUp -> {
|
||||
if (mUp.member().hasRole("compute"))
|
||||
nodes.add(mUp.member().address());
|
||||
})
|
||||
.match(MemberEvent.class, event -> {
|
||||
nodes.remove(event.member().address());
|
||||
})
|
||||
.match(UnreachableMember.class, unreachable -> {
|
||||
nodes.remove(unreachable.member().address());
|
||||
})
|
||||
.match(ReachableMember.class, reachable -> {
|
||||
if (reachable.member().hasRole("compute"))
|
||||
nodes.add(reachable.member().address());
|
||||
|
||||
})
|
||||
.build();
|
||||
.matchEquals(
|
||||
"tick",
|
||||
x -> !nodes.isEmpty(),
|
||||
x -> {
|
||||
// just pick any one
|
||||
List<Address> nodesList = new ArrayList<Address>(nodes);
|
||||
Address address =
|
||||
nodesList.get(ThreadLocalRandom.current().nextInt(nodesList.size()));
|
||||
ActorSelection service = getContext().actorSelection(address + servicePath);
|
||||
service.tell(new StatsJob("this is the text that will be analyzed"), getSelf());
|
||||
})
|
||||
.match(StatsResult.class, System.out::println)
|
||||
.match(JobFailed.class, System.out::println)
|
||||
.match(
|
||||
CurrentClusterState.class,
|
||||
state -> {
|
||||
nodes.clear();
|
||||
for (Member member : state.getMembers()) {
|
||||
if (member.hasRole("compute") && member.status().equals(MemberStatus.up())) {
|
||||
nodes.add(member.address());
|
||||
}
|
||||
}
|
||||
})
|
||||
.match(
|
||||
MemberUp.class,
|
||||
mUp -> {
|
||||
if (mUp.member().hasRole("compute")) nodes.add(mUp.member().address());
|
||||
})
|
||||
.match(
|
||||
MemberEvent.class,
|
||||
event -> {
|
||||
nodes.remove(event.member().address());
|
||||
})
|
||||
.match(
|
||||
UnreachableMember.class,
|
||||
unreachable -> {
|
||||
nodes.remove(unreachable.member().address());
|
||||
})
|
||||
.match(
|
||||
ReachableMember.class,
|
||||
reachable -> {
|
||||
if (reachable.member().hasRole("compute")) nodes.add(reachable.member().address());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,11 +13,7 @@ public class StatsSampleOneMasterClientMain {
|
|||
|
||||
public static void main(String[] args) {
|
||||
// note that client is not a compute node, role not defined
|
||||
ActorSystem system = ActorSystem.create("ClusterSystem",
|
||||
ConfigFactory.load("stats2"));
|
||||
system.actorOf(Props.create(StatsSampleClient.class, "/user/statsServiceProxy"),
|
||||
"client");
|
||||
|
||||
ActorSystem system = ActorSystem.create("ClusterSystem", ConfigFactory.load("stats2"));
|
||||
system.actorOf(Props.create(StatsSampleClient.class, "/user/statsServiceProxy"), "client");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public class StatsSampleOneMasterMain {
|
|||
|
||||
public static void main(String[] args) {
|
||||
if (args.length == 0) {
|
||||
startup(new String[] { "2551", "2552", "0" });
|
||||
startup(new String[] {"2551", "2552", "0"});
|
||||
StatsSampleOneMasterClientMain.main(new String[0]);
|
||||
} else {
|
||||
startup(args);
|
||||
|
|
@ -29,29 +29,28 @@ public class StatsSampleOneMasterMain {
|
|||
public static void startup(String[] ports) {
|
||||
for (String port : ports) {
|
||||
// Override the configuration of the port
|
||||
Config config = ConfigFactory
|
||||
.parseString("akka.remote.netty.tcp.port=" + port)
|
||||
.withFallback(
|
||||
ConfigFactory.parseString("akka.cluster.roles = [compute]"))
|
||||
.withFallback(ConfigFactory.load("stats2"));
|
||||
Config config =
|
||||
ConfigFactory.parseString("akka.remote.netty.tcp.port=" + port)
|
||||
.withFallback(ConfigFactory.parseString("akka.cluster.roles = [compute]"))
|
||||
.withFallback(ConfigFactory.load("stats2"));
|
||||
|
||||
ActorSystem system = ActorSystem.create("ClusterSystem", config);
|
||||
|
||||
//#create-singleton-manager
|
||||
ClusterSingletonManagerSettings settings = ClusterSingletonManagerSettings.create(system)
|
||||
.withRole("compute");
|
||||
system.actorOf(ClusterSingletonManager.props(
|
||||
Props.create(StatsService.class), PoisonPill.getInstance(), settings),
|
||||
// #create-singleton-manager
|
||||
ClusterSingletonManagerSettings settings =
|
||||
ClusterSingletonManagerSettings.create(system).withRole("compute");
|
||||
system.actorOf(
|
||||
ClusterSingletonManager.props(
|
||||
Props.create(StatsService.class), PoisonPill.getInstance(), settings),
|
||||
"statsService");
|
||||
//#create-singleton-manager
|
||||
// #create-singleton-manager
|
||||
|
||||
//#singleton-proxy
|
||||
// #singleton-proxy
|
||||
ClusterSingletonProxySettings proxySettings =
|
||||
ClusterSingletonProxySettings.create(system).withRole("compute");
|
||||
system.actorOf(ClusterSingletonProxy.props("/user/statsService",
|
||||
proxySettings), "statsServiceProxy");
|
||||
//#singleton-proxy
|
||||
system.actorOf(
|
||||
ClusterSingletonProxy.props("/user/statsService", proxySettings), "statsServiceProxy");
|
||||
// #singleton-proxy
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,66 +22,74 @@ import java.util.Collections;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
//#service
|
||||
// #service
|
||||
public class StatsService extends AbstractActor {
|
||||
|
||||
// This router is used both with lookup and deploy of routees. If you
|
||||
// have a router with only lookup of routees you can use Props.empty()
|
||||
// instead of Props.create(StatsWorker.class).
|
||||
ActorRef workerRouter = getContext().actorOf(
|
||||
FromConfig.getInstance().props(Props.create(StatsWorker.class)),
|
||||
"workerRouter");
|
||||
ActorRef workerRouter =
|
||||
getContext()
|
||||
.actorOf(FromConfig.getInstance().props(Props.create(StatsWorker.class)), "workerRouter");
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(StatsJob.class, job -> !job.getText().isEmpty(), job -> {
|
||||
String[] words = job.getText().split(" ");
|
||||
ActorRef replyTo = getSender();
|
||||
.match(
|
||||
StatsJob.class,
|
||||
job -> !job.getText().isEmpty(),
|
||||
job -> {
|
||||
String[] words = job.getText().split(" ");
|
||||
ActorRef replyTo = getSender();
|
||||
|
||||
// create actor that collects replies from workers
|
||||
ActorRef aggregator = getContext().actorOf(
|
||||
Props.create(StatsAggregator.class, words.length, replyTo));
|
||||
// create actor that collects replies from workers
|
||||
ActorRef aggregator =
|
||||
getContext().actorOf(Props.create(StatsAggregator.class, words.length, replyTo));
|
||||
|
||||
// send each word to a worker
|
||||
for (String word : words) {
|
||||
workerRouter.tell(new ConsistentHashableEnvelope(word, word),
|
||||
aggregator);
|
||||
}
|
||||
|
||||
})
|
||||
.build();
|
||||
// send each word to a worker
|
||||
for (String word : words) {
|
||||
workerRouter.tell(new ConsistentHashableEnvelope(word, word), aggregator);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#service
|
||||
// #service
|
||||
|
||||
//not used, only for documentation
|
||||
// not used, only for documentation
|
||||
abstract class StatsService2 extends AbstractActor {
|
||||
//#router-lookup-in-code
|
||||
// #router-lookup-in-code
|
||||
int totalInstances = 100;
|
||||
Iterable<String> routeesPaths = Collections
|
||||
.singletonList("/user/statsWorker");
|
||||
Iterable<String> routeesPaths = Collections.singletonList("/user/statsWorker");
|
||||
boolean allowLocalRoutees = true;
|
||||
Set<String> useRoles = new HashSet<>(Arrays.asList("compute"));
|
||||
ActorRef workerRouter = getContext().actorOf(
|
||||
new ClusterRouterGroup(new ConsistentHashingGroup(routeesPaths),
|
||||
new ClusterRouterGroupSettings(totalInstances, routeesPaths,
|
||||
allowLocalRoutees, useRoles)).props(), "workerRouter2");
|
||||
//#router-lookup-in-code
|
||||
ActorRef workerRouter =
|
||||
getContext()
|
||||
.actorOf(
|
||||
new ClusterRouterGroup(
|
||||
new ConsistentHashingGroup(routeesPaths),
|
||||
new ClusterRouterGroupSettings(
|
||||
totalInstances, routeesPaths, allowLocalRoutees, useRoles))
|
||||
.props(),
|
||||
"workerRouter2");
|
||||
// #router-lookup-in-code
|
||||
}
|
||||
|
||||
//not used, only for documentation
|
||||
// not used, only for documentation
|
||||
abstract class StatsService3 extends AbstractActor {
|
||||
//#router-deploy-in-code
|
||||
// #router-deploy-in-code
|
||||
int totalInstances = 100;
|
||||
int maxInstancesPerNode = 3;
|
||||
boolean allowLocalRoutees = false;
|
||||
Set<String> useRoles = new HashSet<>(Arrays.asList("compute"));
|
||||
ActorRef workerRouter = getContext().actorOf(
|
||||
new ClusterRouterPool(new ConsistentHashingPool(0),
|
||||
new ClusterRouterPoolSettings(totalInstances, maxInstancesPerNode,
|
||||
allowLocalRoutees, useRoles)).props(Props
|
||||
.create(StatsWorker.class)), "workerRouter3");
|
||||
//#router-deploy-in-code
|
||||
ActorRef workerRouter =
|
||||
getContext()
|
||||
.actorOf(
|
||||
new ClusterRouterPool(
|
||||
new ConsistentHashingPool(0),
|
||||
new ClusterRouterPoolSettings(
|
||||
totalInstances, maxInstancesPerNode, allowLocalRoutees, useRoles))
|
||||
.props(Props.create(StatsWorker.class)),
|
||||
"workerRouter3");
|
||||
// #router-deploy-in-code
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import java.util.Map;
|
|||
|
||||
import akka.actor.AbstractActor;
|
||||
|
||||
//#worker
|
||||
// #worker
|
||||
public class StatsWorker extends AbstractActor {
|
||||
|
||||
Map<String, Integer> cache = new HashMap<String, Integer>();
|
||||
|
|
@ -17,15 +17,17 @@ public class StatsWorker extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(String.class, word -> {
|
||||
Integer length = cache.get(word);
|
||||
if (length == null) {
|
||||
length = word.length();
|
||||
cache.put(word, length);
|
||||
}
|
||||
getSender().tell(length, getSelf());
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
String.class,
|
||||
word -> {
|
||||
Integer length = cache.get(word);
|
||||
if (length == null) {
|
||||
length = word.length();
|
||||
cache.put(word, length);
|
||||
}
|
||||
getSender().tell(length, getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#worker
|
||||
// #worker
|
||||
|
|
|
|||
|
|
@ -14,18 +14,18 @@ import akka.cluster.ClusterEvent.MemberUp;
|
|||
import akka.cluster.Member;
|
||||
import akka.cluster.MemberStatus;
|
||||
|
||||
//#backend
|
||||
// #backend
|
||||
public class TransformationBackend extends AbstractActor {
|
||||
|
||||
Cluster cluster = Cluster.get(getContext().getSystem());
|
||||
|
||||
//subscribe to cluster changes, MemberUp
|
||||
// subscribe to cluster changes, MemberUp
|
||||
@Override
|
||||
public void preStart() {
|
||||
cluster.subscribe(getSelf(), MemberUp.class);
|
||||
}
|
||||
|
||||
//re-subscribe when restart
|
||||
// re-subscribe when restart
|
||||
@Override
|
||||
public void postStop() {
|
||||
cluster.unsubscribe(getSelf());
|
||||
|
|
@ -34,27 +34,33 @@ public class TransformationBackend extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(TransformationJob.class, job -> {
|
||||
getSender().tell(new TransformationResult(job.getText().toUpperCase()),
|
||||
getSelf());
|
||||
})
|
||||
.match(CurrentClusterState.class, state -> {
|
||||
for (Member member : state.getMembers()) {
|
||||
if (member.status().equals(MemberStatus.up())) {
|
||||
register(member);
|
||||
}
|
||||
}
|
||||
})
|
||||
.match(MemberUp.class, mUp -> {
|
||||
register(mUp.member());
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
TransformationJob.class,
|
||||
job -> {
|
||||
getSender().tell(new TransformationResult(job.getText().toUpperCase()), getSelf());
|
||||
})
|
||||
.match(
|
||||
CurrentClusterState.class,
|
||||
state -> {
|
||||
for (Member member : state.getMembers()) {
|
||||
if (member.status().equals(MemberStatus.up())) {
|
||||
register(member);
|
||||
}
|
||||
}
|
||||
})
|
||||
.match(
|
||||
MemberUp.class,
|
||||
mUp -> {
|
||||
register(mUp.member());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
void register(Member member) {
|
||||
if (member.hasRole("frontend"))
|
||||
getContext().actorSelection(member.address() + "/user/frontend").tell(
|
||||
BACKEND_REGISTRATION, getSelf());
|
||||
getContext()
|
||||
.actorSelection(member.address() + "/user/frontend")
|
||||
.tell(BACKEND_REGISTRATION, getSelf());
|
||||
}
|
||||
}
|
||||
//#backend
|
||||
// #backend
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import akka.actor.ActorRef;
|
|||
import akka.actor.Terminated;
|
||||
import akka.actor.AbstractActor;
|
||||
|
||||
//#frontend
|
||||
// #frontend
|
||||
public class TransformationFrontend extends AbstractActor {
|
||||
|
||||
List<ActorRef> backends = new ArrayList<ActorRef>();
|
||||
|
|
@ -24,25 +24,31 @@ public class TransformationFrontend extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(TransformationJob.class, job -> backends.isEmpty(), job -> {
|
||||
getSender().tell(
|
||||
new JobFailed("Service unavailable, try again later", job),
|
||||
getSender());
|
||||
})
|
||||
.match(TransformationJob.class, job -> {
|
||||
jobCounter++;
|
||||
backends.get(jobCounter % backends.size())
|
||||
.forward(job, getContext());
|
||||
})
|
||||
.matchEquals(BACKEND_REGISTRATION, x -> {
|
||||
getContext().watch(getSender());
|
||||
backends.add(getSender());
|
||||
})
|
||||
.match(Terminated.class, terminated -> {
|
||||
backends.remove(terminated.getActor());
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
TransformationJob.class,
|
||||
job -> backends.isEmpty(),
|
||||
job -> {
|
||||
getSender()
|
||||
.tell(new JobFailed("Service unavailable, try again later", job), getSender());
|
||||
})
|
||||
.match(
|
||||
TransformationJob.class,
|
||||
job -> {
|
||||
jobCounter++;
|
||||
backends.get(jobCounter % backends.size()).forward(job, getContext());
|
||||
})
|
||||
.matchEquals(
|
||||
BACKEND_REGISTRATION,
|
||||
x -> {
|
||||
getContext().watch(getSender());
|
||||
backends.add(getSender());
|
||||
})
|
||||
.match(
|
||||
Terminated.class,
|
||||
terminated -> {
|
||||
backends.remove(terminated.getActor());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
//#frontend
|
||||
// #frontend
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ package jdocs.cluster;
|
|||
|
||||
import java.io.Serializable;
|
||||
|
||||
//#messages
|
||||
// #messages
|
||||
public interface TransformationMessages {
|
||||
|
||||
public static class TransformationJob implements Serializable {
|
||||
|
|
@ -62,6 +62,5 @@ public interface TransformationMessages {
|
|||
}
|
||||
|
||||
public static final String BACKEND_REGISTRATION = "BackendRegistration";
|
||||
|
||||
}
|
||||
//#messages
|
||||
// #messages
|
||||
|
|
|
|||
|
|
@ -9,23 +9,26 @@ import akka.actor.ActorRef;
|
|||
import akka.actor.Props;
|
||||
import akka.actor.SupervisorStrategy;
|
||||
|
||||
//#singleton-supervisor-actor-usage-imports
|
||||
// #singleton-supervisor-actor-usage-imports
|
||||
import akka.actor.PoisonPill;
|
||||
import akka.actor.Props;
|
||||
import akka.cluster.singleton.ClusterSingletonManager;
|
||||
import akka.cluster.singleton.ClusterSingletonManagerSettings;
|
||||
//#singleton-supervisor-actor-usage-imports
|
||||
// #singleton-supervisor-actor-usage-imports
|
||||
|
||||
abstract class ClusterSingletonSupervision extends AbstractActor {
|
||||
|
||||
public ActorRef createSingleton(String name, Props props, SupervisorStrategy supervisorStrategy) {
|
||||
//#singleton-supervisor-actor-usage
|
||||
return getContext().system().actorOf(
|
||||
ClusterSingletonManager.props(
|
||||
Props.create(SupervisorActor.class, () -> new SupervisorActor(props, supervisorStrategy)),
|
||||
PoisonPill.getInstance(),
|
||||
ClusterSingletonManagerSettings.create(getContext().system())),
|
||||
name = name);
|
||||
//#singleton-supervisor-actor-usage
|
||||
// #singleton-supervisor-actor-usage
|
||||
return getContext()
|
||||
.system()
|
||||
.actorOf(
|
||||
ClusterSingletonManager.props(
|
||||
Props.create(
|
||||
SupervisorActor.class, () -> new SupervisorActor(props, supervisorStrategy)),
|
||||
PoisonPill.getInstance(),
|
||||
ClusterSingletonManagerSettings.create(getContext().system())),
|
||||
name = name);
|
||||
// #singleton-supervisor-actor-usage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package jdocs.cluster.singleton;
|
||||
|
||||
//#singleton-supervisor-actor
|
||||
// #singleton-supervisor-actor
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.AbstractActor.Receive;
|
||||
import akka.actor.ActorRef;
|
||||
|
|
@ -15,6 +15,7 @@ public class SupervisorActor extends AbstractActor {
|
|||
final Props childProps;
|
||||
final SupervisorStrategy supervisorStrategy;
|
||||
final ActorRef child;
|
||||
|
||||
SupervisorActor(Props childProps, SupervisorStrategy supervisorStrategy) {
|
||||
this.childProps = childProps;
|
||||
this.supervisorStrategy = supervisorStrategy;
|
||||
|
|
@ -28,9 +29,7 @@ public class SupervisorActor extends AbstractActor {
|
|||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchAny(msg -> child.forward(msg, getContext()))
|
||||
.build();
|
||||
return receiveBuilder().matchAny(msg -> child.forward(msg, getContext())).build();
|
||||
}
|
||||
}
|
||||
//#singleton-supervisor-actor
|
||||
// #singleton-supervisor-actor
|
||||
|
|
|
|||
|
|
@ -9,26 +9,20 @@ import com.typesafe.config.*;
|
|||
|
||||
public class ConfigDoc {
|
||||
public ActorSystem createConfiguredSystem() {
|
||||
//#java-custom-config
|
||||
// #java-custom-config
|
||||
// make a Config with just your special setting
|
||||
Config myConfig =
|
||||
ConfigFactory.parseString("something=somethingElse");
|
||||
Config myConfig = ConfigFactory.parseString("something=somethingElse");
|
||||
// load the normal config stack (system props,
|
||||
// then application.conf, then reference.conf)
|
||||
Config regularConfig =
|
||||
ConfigFactory.load();
|
||||
Config regularConfig = ConfigFactory.load();
|
||||
// override regular stack with myConfig
|
||||
Config combined =
|
||||
myConfig.withFallback(regularConfig);
|
||||
Config combined = myConfig.withFallback(regularConfig);
|
||||
// put the result in between the overrides
|
||||
// (system props) and defaults again
|
||||
Config complete =
|
||||
ConfigFactory.load(combined);
|
||||
Config complete = ConfigFactory.load(combined);
|
||||
// create ActorSystem
|
||||
ActorSystem system =
|
||||
ActorSystem.create("myname", complete);
|
||||
//#java-custom-config
|
||||
ActorSystem system = ActorSystem.create("myname", complete);
|
||||
// #java-custom-config
|
||||
return system;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package jdocs.ddata;
|
||||
|
||||
//#data-bot
|
||||
// #data-bot
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
|
|
@ -30,13 +30,20 @@ public class DataBot extends AbstractActor {
|
|||
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
private final ActorRef replicator =
|
||||
DistributedData.get(getContext().getSystem()).replicator();
|
||||
private final ActorRef replicator = DistributedData.get(getContext().getSystem()).replicator();
|
||||
private final Cluster node = Cluster.get(getContext().getSystem());
|
||||
|
||||
private final Cancellable tickTask = getContext().getSystem().scheduler().schedule(
|
||||
Duration.ofSeconds(5), Duration.ofSeconds(5), getSelf(), TICK,
|
||||
getContext().getDispatcher(), getSelf());
|
||||
private final Cancellable tickTask =
|
||||
getContext()
|
||||
.getSystem()
|
||||
.scheduler()
|
||||
.schedule(
|
||||
Duration.ofSeconds(5),
|
||||
Duration.ofSeconds(5),
|
||||
getSelf(),
|
||||
TICK,
|
||||
getContext().getDispatcher(),
|
||||
getSelf());
|
||||
|
||||
private final Key<ORSet<String>> dataKey = ORSetKey.create("key");
|
||||
|
||||
|
|
@ -44,37 +51,33 @@ public class DataBot extends AbstractActor {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(String.class, a -> a.equals(TICK), a -> receiveTick())
|
||||
.match(Changed.class, c -> c.key().equals(dataKey), c -> receiveChanged((Changed<ORSet<String>>) c))
|
||||
.match(UpdateResponse.class, r -> receiveUpdateResponse())
|
||||
.build();
|
||||
.match(String.class, a -> a.equals(TICK), a -> receiveTick())
|
||||
.match(
|
||||
Changed.class,
|
||||
c -> c.key().equals(dataKey),
|
||||
c -> receiveChanged((Changed<ORSet<String>>) c))
|
||||
.match(UpdateResponse.class, r -> receiveUpdateResponse())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
private void receiveTick() {
|
||||
String s = String.valueOf((char) ThreadLocalRandom.current().nextInt(97, 123));
|
||||
if (ThreadLocalRandom.current().nextBoolean()) {
|
||||
// add
|
||||
log.info("Adding: {}", s);
|
||||
Update<ORSet<String>> update = new Update<>(
|
||||
dataKey,
|
||||
ORSet.create(),
|
||||
Replicator.writeLocal(),
|
||||
curr -> curr.add(node, s));
|
||||
replicator.tell(update, getSelf());
|
||||
Update<ORSet<String>> update =
|
||||
new Update<>(dataKey, ORSet.create(), Replicator.writeLocal(), curr -> curr.add(node, s));
|
||||
replicator.tell(update, getSelf());
|
||||
} else {
|
||||
// remove
|
||||
log.info("Removing: {}", s);
|
||||
Update<ORSet<String>> update = new Update<>(
|
||||
dataKey,
|
||||
ORSet.create(),
|
||||
Replicator.writeLocal(),
|
||||
curr -> curr.remove(node, s));
|
||||
Update<ORSet<String>> update =
|
||||
new Update<>(
|
||||
dataKey, ORSet.create(), Replicator.writeLocal(), curr -> curr.remove(node, s));
|
||||
replicator.tell(update, getSelf());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void receiveChanged(Changed<ORSet<String>> c) {
|
||||
ORSet<String> data = c.dataValue();
|
||||
log.info("Current elements: {}", data.getElements());
|
||||
|
|
@ -84,7 +87,6 @@ public class DataBot extends AbstractActor {
|
|||
// ignore
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void preStart() {
|
||||
Subscribe<ORSet<String>> subscribe = new Subscribe<>(dataKey, getSelf());
|
||||
|
|
@ -92,9 +94,8 @@ public class DataBot extends AbstractActor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void postStop(){
|
||||
public void postStop() {
|
||||
tickTask.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
//#data-bot
|
||||
// #data-bot
|
||||
|
|
|
|||
|
|
@ -31,14 +31,14 @@ import static akka.cluster.ddata.Replicator.*;
|
|||
|
||||
@SuppressWarnings({"unchecked", "unused"})
|
||||
public class DistributedDataDocTest extends AbstractJavaTest {
|
||||
|
||||
|
||||
static ActorSystem system;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
system = ActorSystem.create("DistributedDataDocTest",
|
||||
ConfigFactory.parseString(DistributedDataDocSpec.config()));
|
||||
system =
|
||||
ActorSystem.create(
|
||||
"DistributedDataDocTest", ConfigFactory.parseString(DistributedDataDocSpec.config()));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
|
@ -48,11 +48,11 @@ public class DistributedDataDocTest extends AbstractJavaTest {
|
|||
}
|
||||
|
||||
static
|
||||
//#update
|
||||
// #update
|
||||
class DemonstrateUpdate extends AbstractActor {
|
||||
final SelfUniqueAddress node = DistributedData.get(getContext().getSystem()).selfUniqueAddress();
|
||||
final ActorRef replicator =
|
||||
DistributedData.get(getContext().getSystem()).replicator();
|
||||
final SelfUniqueAddress node =
|
||||
DistributedData.get(getContext().getSystem()).selfUniqueAddress();
|
||||
final ActorRef replicator = DistributedData.get(getContext().getSystem()).replicator();
|
||||
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
final Key<GSet<String>> set1Key = GSetKey.create("set1");
|
||||
|
|
@ -62,260 +62,310 @@ public class DistributedDataDocTest extends AbstractJavaTest {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
ReceiveBuilder b = receiveBuilder();
|
||||
|
||||
b.matchEquals("demonstrate update", msg -> {
|
||||
replicator.tell(new Replicator.Update<PNCounter>(counter1Key, PNCounter.create(),
|
||||
Replicator.writeLocal(), curr -> curr.increment(node, 1)), getSelf());
|
||||
|
||||
final WriteConsistency writeTo3 = new WriteTo(3, Duration.ofSeconds(1));
|
||||
replicator.tell(new Replicator.Update<GSet<String>>(set1Key, GSet.create(),
|
||||
writeTo3, curr -> curr.add("hello")), getSelf());
|
||||
b.matchEquals(
|
||||
"demonstrate update",
|
||||
msg -> {
|
||||
replicator.tell(
|
||||
new Replicator.Update<PNCounter>(
|
||||
counter1Key,
|
||||
PNCounter.create(),
|
||||
Replicator.writeLocal(),
|
||||
curr -> curr.increment(node, 1)),
|
||||
getSelf());
|
||||
|
||||
final WriteConsistency writeMajority =
|
||||
new WriteMajority(Duration.ofSeconds(5));
|
||||
replicator.tell(new Replicator.Update<ORSet<String>>(set2Key, ORSet.create(),
|
||||
writeMajority, curr -> curr.add(node, "hello")), getSelf());
|
||||
final WriteConsistency writeTo3 = new WriteTo(3, Duration.ofSeconds(1));
|
||||
replicator.tell(
|
||||
new Replicator.Update<GSet<String>>(
|
||||
set1Key, GSet.create(), writeTo3, curr -> curr.add("hello")),
|
||||
getSelf());
|
||||
|
||||
final WriteConsistency writeAll = new WriteAll(Duration.ofSeconds(5));
|
||||
replicator.tell(new Replicator.Update<Flag>(activeFlagKey, Flag.create(),
|
||||
writeAll, curr -> curr.switchOn()), getSelf());
|
||||
});
|
||||
//#update
|
||||
|
||||
//#update-response1
|
||||
b.match(UpdateSuccess.class, a -> a.key().equals(counter1Key), a -> {
|
||||
// ok
|
||||
});
|
||||
//#update-response1
|
||||
|
||||
//#update-response2
|
||||
b.match(UpdateSuccess.class, a -> a.key().equals(set1Key), a -> {
|
||||
// ok
|
||||
})
|
||||
.match(UpdateTimeout.class, a -> a.key().equals(set1Key), a -> {
|
||||
// write to 3 nodes failed within 1.second
|
||||
});
|
||||
//#update-response2
|
||||
|
||||
//#update
|
||||
final WriteConsistency writeMajority = new WriteMajority(Duration.ofSeconds(5));
|
||||
replicator.tell(
|
||||
new Replicator.Update<ORSet<String>>(
|
||||
set2Key, ORSet.create(), writeMajority, curr -> curr.add(node, "hello")),
|
||||
getSelf());
|
||||
|
||||
final WriteConsistency writeAll = new WriteAll(Duration.ofSeconds(5));
|
||||
replicator.tell(
|
||||
new Replicator.Update<Flag>(
|
||||
activeFlagKey, Flag.create(), writeAll, curr -> curr.switchOn()),
|
||||
getSelf());
|
||||
});
|
||||
// #update
|
||||
|
||||
// #update-response1
|
||||
b.match(
|
||||
UpdateSuccess.class,
|
||||
a -> a.key().equals(counter1Key),
|
||||
a -> {
|
||||
// ok
|
||||
});
|
||||
// #update-response1
|
||||
|
||||
// #update-response2
|
||||
b.match(
|
||||
UpdateSuccess.class,
|
||||
a -> a.key().equals(set1Key),
|
||||
a -> {
|
||||
// ok
|
||||
})
|
||||
.match(
|
||||
UpdateTimeout.class,
|
||||
a -> a.key().equals(set1Key),
|
||||
a -> {
|
||||
// write to 3 nodes failed within 1.second
|
||||
});
|
||||
// #update-response2
|
||||
|
||||
// #update
|
||||
return b.build();
|
||||
}
|
||||
}
|
||||
//#update
|
||||
// #update
|
||||
|
||||
static
|
||||
//#update-request-context
|
||||
// #update-request-context
|
||||
class DemonstrateUpdateWithRequestContext extends AbstractActor {
|
||||
final Cluster node = Cluster.get(getContext().getSystem());
|
||||
final ActorRef replicator =
|
||||
DistributedData.get(getContext().getSystem()).replicator();
|
||||
final ActorRef replicator = DistributedData.get(getContext().getSystem()).replicator();
|
||||
|
||||
final WriteConsistency writeTwo = new WriteTo(2, Duration.ofSeconds(3));
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(String.class, a -> a.equals("increment"), a -> {
|
||||
// incoming command to increase the counter
|
||||
Optional<Object> reqContext = Optional.of(getSender());
|
||||
Replicator.Update<PNCounter> upd = new Replicator.Update<PNCounter>(counter1Key,
|
||||
PNCounter.create(), writeTwo, reqContext, curr -> curr.increment(node, 1));
|
||||
replicator.tell(upd, getSelf());
|
||||
})
|
||||
|
||||
.match(UpdateSuccess.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell("ack", getSelf());
|
||||
})
|
||||
|
||||
.match(UpdateTimeout.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell("nack", getSelf());
|
||||
})
|
||||
|
||||
.build();
|
||||
}
|
||||
.match(
|
||||
String.class,
|
||||
a -> a.equals("increment"),
|
||||
a -> {
|
||||
// incoming command to increase the counter
|
||||
Optional<Object> reqContext = Optional.of(getSender());
|
||||
Replicator.Update<PNCounter> upd =
|
||||
new Replicator.Update<PNCounter>(
|
||||
counter1Key,
|
||||
PNCounter.create(),
|
||||
writeTwo,
|
||||
reqContext,
|
||||
curr -> curr.increment(node, 1));
|
||||
replicator.tell(upd, getSelf());
|
||||
})
|
||||
.match(
|
||||
UpdateSuccess.class,
|
||||
a -> a.key().equals(counter1Key),
|
||||
a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell("ack", getSelf());
|
||||
})
|
||||
.match(
|
||||
UpdateTimeout.class,
|
||||
a -> a.key().equals(counter1Key),
|
||||
a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell("nack", getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#update-request-context
|
||||
// #update-request-context
|
||||
|
||||
static
|
||||
//#get
|
||||
// #get
|
||||
class DemonstrateGet extends AbstractActor {
|
||||
final ActorRef replicator =
|
||||
DistributedData.get(getContext().getSystem()).replicator();
|
||||
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
final Key<GSet<String>> set1Key = GSetKey.create("set1");
|
||||
final Key<ORSet<String>> set2Key = ORSetKey.create("set2");
|
||||
final Key<Flag> activeFlagKey = FlagKey.create("active");
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
ReceiveBuilder b = receiveBuilder();
|
||||
|
||||
b.matchEquals("demonstrate get", msg -> {
|
||||
final ActorRef replicator = DistributedData.get(getContext().getSystem()).replicator();
|
||||
|
||||
replicator.tell(new Replicator.Get<PNCounter>(counter1Key,
|
||||
Replicator.readLocal()), getSelf());
|
||||
|
||||
final ReadConsistency readFrom3 = new ReadFrom(3, Duration.ofSeconds(1));
|
||||
replicator.tell(new Replicator.Get<GSet<String>>(set1Key,
|
||||
readFrom3), getSelf());
|
||||
|
||||
final ReadConsistency readMajority = new ReadMajority(Duration.ofSeconds(5));
|
||||
replicator.tell(new Replicator.Get<ORSet<String>>(set2Key,
|
||||
readMajority), getSelf());
|
||||
|
||||
final ReadConsistency readAll = new ReadAll(Duration.ofSeconds(5));
|
||||
replicator.tell(new Replicator.Get<Flag>(activeFlagKey,
|
||||
readAll), getSelf());
|
||||
|
||||
});
|
||||
//#get
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
final Key<GSet<String>> set1Key = GSetKey.create("set1");
|
||||
final Key<ORSet<String>> set2Key = ORSetKey.create("set2");
|
||||
final Key<Flag> activeFlagKey = FlagKey.create("active");
|
||||
|
||||
//#get-response1
|
||||
b.match(GetSuccess.class, a -> a.key().equals(counter1Key), a -> {
|
||||
GetSuccess<PNCounter> g = a;
|
||||
BigInteger value = g.dataValue().getValue();
|
||||
}).
|
||||
match(NotFound.class, a -> a.key().equals(counter1Key), a -> {
|
||||
// key counter1 does not exist
|
||||
});
|
||||
//#get-response1
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
ReceiveBuilder b = receiveBuilder();
|
||||
|
||||
//#get-response2
|
||||
b.match(GetSuccess.class, a -> a.key().equals(set1Key), a -> {
|
||||
GetSuccess<GSet<String>> g = a;
|
||||
Set<String> value = g.dataValue().getElements();
|
||||
}).
|
||||
match(GetFailure.class, a -> a.key().equals(set1Key), a -> {
|
||||
// read from 3 nodes failed within 1.second
|
||||
}).
|
||||
match(NotFound.class, a -> a.key().equals(set1Key), a -> {
|
||||
// key set1 does not exist
|
||||
});
|
||||
//#get-response2
|
||||
b.matchEquals(
|
||||
"demonstrate get",
|
||||
msg -> {
|
||||
replicator.tell(
|
||||
new Replicator.Get<PNCounter>(counter1Key, Replicator.readLocal()), getSelf());
|
||||
|
||||
//#get
|
||||
final ReadConsistency readFrom3 = new ReadFrom(3, Duration.ofSeconds(1));
|
||||
replicator.tell(new Replicator.Get<GSet<String>>(set1Key, readFrom3), getSelf());
|
||||
|
||||
final ReadConsistency readMajority = new ReadMajority(Duration.ofSeconds(5));
|
||||
replicator.tell(new Replicator.Get<ORSet<String>>(set2Key, readMajority), getSelf());
|
||||
|
||||
final ReadConsistency readAll = new ReadAll(Duration.ofSeconds(5));
|
||||
replicator.tell(new Replicator.Get<Flag>(activeFlagKey, readAll), getSelf());
|
||||
});
|
||||
// #get
|
||||
|
||||
// #get-response1
|
||||
b.match(
|
||||
GetSuccess.class,
|
||||
a -> a.key().equals(counter1Key),
|
||||
a -> {
|
||||
GetSuccess<PNCounter> g = a;
|
||||
BigInteger value = g.dataValue().getValue();
|
||||
})
|
||||
.match(
|
||||
NotFound.class,
|
||||
a -> a.key().equals(counter1Key),
|
||||
a -> {
|
||||
// key counter1 does not exist
|
||||
});
|
||||
// #get-response1
|
||||
|
||||
// #get-response2
|
||||
b.match(
|
||||
GetSuccess.class,
|
||||
a -> a.key().equals(set1Key),
|
||||
a -> {
|
||||
GetSuccess<GSet<String>> g = a;
|
||||
Set<String> value = g.dataValue().getElements();
|
||||
})
|
||||
.match(
|
||||
GetFailure.class,
|
||||
a -> a.key().equals(set1Key),
|
||||
a -> {
|
||||
// read from 3 nodes failed within 1.second
|
||||
})
|
||||
.match(
|
||||
NotFound.class,
|
||||
a -> a.key().equals(set1Key),
|
||||
a -> {
|
||||
// key set1 does not exist
|
||||
});
|
||||
// #get-response2
|
||||
|
||||
// #get
|
||||
return b.build();
|
||||
}
|
||||
}
|
||||
//#get
|
||||
// #get
|
||||
|
||||
static
|
||||
//#get-request-context
|
||||
// #get-request-context
|
||||
class DemonstrateGetWithRequestContext extends AbstractActor {
|
||||
final ActorRef replicator =
|
||||
DistributedData.get(getContext().getSystem()).replicator();
|
||||
|
||||
final ReadConsistency readTwo = new ReadFrom(2, Duration.ofSeconds(3));
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(String.class, a -> a.equals("get-count"), a -> {
|
||||
// incoming request to retrieve current value of the counter
|
||||
Optional<Object> reqContext = Optional.of(getSender());
|
||||
replicator.tell(new Replicator.Get<PNCounter>(counter1Key,
|
||||
readTwo), getSelf());
|
||||
})
|
||||
final ActorRef replicator = DistributedData.get(getContext().getSystem()).replicator();
|
||||
|
||||
.match(GetSuccess.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
GetSuccess<PNCounter> g = a;
|
||||
long value = g.dataValue().getValue().longValue();
|
||||
replyTo.tell(value, getSelf());
|
||||
})
|
||||
|
||||
.match(GetFailure.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell(-1L, getSelf());
|
||||
})
|
||||
|
||||
.match(NotFound.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell(0L, getSelf());
|
||||
})
|
||||
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#get-request-context
|
||||
|
||||
static
|
||||
//#subscribe
|
||||
class DemonstrateSubscribe extends AbstractActor {
|
||||
final ActorRef replicator =
|
||||
DistributedData.get(getContext().getSystem()).replicator();
|
||||
final ReadConsistency readTwo = new ReadFrom(2, Duration.ofSeconds(3));
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
|
||||
BigInteger currentValue = BigInteger.valueOf(0);
|
||||
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Changed.class, a -> a.key().equals(counter1Key), a -> {
|
||||
Changed<PNCounter> g = a;
|
||||
currentValue = g.dataValue().getValue();
|
||||
})
|
||||
.match(String.class, a -> a.equals("get-count"), a -> {
|
||||
// incoming request to retrieve current value of the counter
|
||||
getSender().tell(currentValue, getSender());
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
String.class,
|
||||
a -> a.equals("get-count"),
|
||||
a -> {
|
||||
// incoming request to retrieve current value of the counter
|
||||
Optional<Object> reqContext = Optional.of(getSender());
|
||||
replicator.tell(new Replicator.Get<PNCounter>(counter1Key, readTwo), getSelf());
|
||||
})
|
||||
.match(
|
||||
GetSuccess.class,
|
||||
a -> a.key().equals(counter1Key),
|
||||
a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
GetSuccess<PNCounter> g = a;
|
||||
long value = g.dataValue().getValue().longValue();
|
||||
replyTo.tell(value, getSelf());
|
||||
})
|
||||
.match(
|
||||
GetFailure.class,
|
||||
a -> a.key().equals(counter1Key),
|
||||
a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell(-1L, getSelf());
|
||||
})
|
||||
.match(
|
||||
NotFound.class,
|
||||
a -> a.key().equals(counter1Key),
|
||||
a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell(0L, getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
// #get-request-context
|
||||
|
||||
static
|
||||
// #subscribe
|
||||
class DemonstrateSubscribe extends AbstractActor {
|
||||
final ActorRef replicator = DistributedData.get(getContext().getSystem()).replicator();
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
|
||||
BigInteger currentValue = BigInteger.valueOf(0);
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(
|
||||
Changed.class,
|
||||
a -> a.key().equals(counter1Key),
|
||||
a -> {
|
||||
Changed<PNCounter> g = a;
|
||||
currentValue = g.dataValue().getValue();
|
||||
})
|
||||
.match(
|
||||
String.class,
|
||||
a -> a.equals("get-count"),
|
||||
a -> {
|
||||
// incoming request to retrieve current value of the counter
|
||||
getSender().tell(currentValue, getSender());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preStart() {
|
||||
// subscribe to changes of the Counter1Key value
|
||||
replicator.tell(new Subscribe<PNCounter>(counter1Key, getSelf()), ActorRef.noSender());
|
||||
}
|
||||
|
||||
}
|
||||
//#subscribe
|
||||
// #subscribe
|
||||
|
||||
static
|
||||
//#delete
|
||||
// #delete
|
||||
class DemonstrateDelete extends AbstractActor {
|
||||
final ActorRef replicator =
|
||||
DistributedData.get(getContext().getSystem()).replicator();
|
||||
|
||||
final ActorRef replicator = DistributedData.get(getContext().getSystem()).replicator();
|
||||
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
final Key<ORSet<String>> set2Key = ORSetKey.create("set2");
|
||||
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("demonstrate delete", msg -> {
|
||||
.matchEquals(
|
||||
"demonstrate delete",
|
||||
msg -> {
|
||||
replicator.tell(
|
||||
new Delete<PNCounter>(counter1Key, Replicator.writeLocal()), getSelf());
|
||||
|
||||
replicator.tell(new Delete<PNCounter>(counter1Key,
|
||||
Replicator.writeLocal()), getSelf());
|
||||
|
||||
final WriteConsistency writeMajority =
|
||||
new WriteMajority(Duration.ofSeconds(5));
|
||||
replicator.tell(new Delete<PNCounter>(counter1Key,
|
||||
writeMajority), getSelf());
|
||||
})
|
||||
.build();
|
||||
final WriteConsistency writeMajority = new WriteMajority(Duration.ofSeconds(5));
|
||||
replicator.tell(new Delete<PNCounter>(counter1Key, writeMajority), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#delete
|
||||
// #delete
|
||||
|
||||
public void demonstratePNCounter() {
|
||||
//#pncounter
|
||||
// #pncounter
|
||||
final SelfUniqueAddress node = DistributedData.get(system).selfUniqueAddress();
|
||||
final PNCounter c0 = PNCounter.create();
|
||||
final PNCounter c1 = c0.increment(node, 1);
|
||||
final PNCounter c2 = c1.increment(node, 7);
|
||||
final PNCounter c3 = c2.decrement(node, 2);
|
||||
System.out.println(c3.value()); // 6
|
||||
//#pncounter
|
||||
// #pncounter
|
||||
}
|
||||
|
||||
public void demonstratePNCounterMap() {
|
||||
//#pncountermap
|
||||
// #pncountermap
|
||||
final SelfUniqueAddress node = DistributedData.get(system).selfUniqueAddress();
|
||||
final PNCounterMap<String> m0 = PNCounterMap.create();
|
||||
final PNCounterMap<String> m1 = m0.increment(node, "a", 7);
|
||||
|
|
@ -323,64 +373,62 @@ public class DistributedDataDocTest extends AbstractJavaTest {
|
|||
final PNCounterMap<String> m3 = m2.increment(node, "b", 1);
|
||||
System.out.println(m3.get("a")); // 5
|
||||
System.out.println(m3.getEntries());
|
||||
//#pncountermap
|
||||
// #pncountermap
|
||||
}
|
||||
|
||||
public void demonstrateGSet() {
|
||||
//#gset
|
||||
// #gset
|
||||
final GSet<String> s0 = GSet.create();
|
||||
final GSet<String> s1 = s0.add("a");
|
||||
final GSet<String> s2 = s1.add("b").add("c");
|
||||
if (s2.contains("a"))
|
||||
System.out.println(s2.getElements()); // a, b, c
|
||||
//#gset
|
||||
if (s2.contains("a")) System.out.println(s2.getElements()); // a, b, c
|
||||
// #gset
|
||||
}
|
||||
|
||||
public void demonstrateORSet() {
|
||||
//#orset
|
||||
// #orset
|
||||
final Cluster node = Cluster.get(system);
|
||||
final ORSet<String> s0 = ORSet.create();
|
||||
final ORSet<String> s1 = s0.add(node, "a");
|
||||
final ORSet<String> s2 = s1.add(node, "b");
|
||||
final ORSet<String> s3 = s2.remove(node, "a");
|
||||
System.out.println(s3.getElements()); // b
|
||||
//#orset
|
||||
// #orset
|
||||
}
|
||||
|
||||
public void demonstrateORMultiMap() {
|
||||
//#ormultimap
|
||||
// #ormultimap
|
||||
final SelfUniqueAddress node = DistributedData.get(system).selfUniqueAddress();
|
||||
final ORMultiMap<String, Integer> m0 = ORMultiMap.create();
|
||||
final ORMultiMap<String, Integer> m1 = m0.put(node, "a",
|
||||
new HashSet<>(Arrays.asList(1, 2, 3)));
|
||||
final ORMultiMap<String, Integer> m1 = m0.put(node, "a", new HashSet<>(Arrays.asList(1, 2, 3)));
|
||||
final ORMultiMap<String, Integer> m2 = m1.addBinding(node, "a", 4);
|
||||
final ORMultiMap<String, Integer> m3 = m2.removeBinding(node, "a", 2);
|
||||
final ORMultiMap<String, Integer> m4 = m3.addBinding(node, "b", 1);
|
||||
System.out.println(m4.getEntries());
|
||||
//#ormultimap
|
||||
// #ormultimap
|
||||
}
|
||||
|
||||
public void demonstrateFlag() {
|
||||
//#flag
|
||||
// #flag
|
||||
final Flag f0 = Flag.create();
|
||||
final Flag f1 = f0.switchOn();
|
||||
System.out.println(f1.enabled());
|
||||
//#flag
|
||||
// #flag
|
||||
}
|
||||
|
||||
@Test
|
||||
public void demonstrateLWWRegister() {
|
||||
//#lwwregister
|
||||
// #lwwregister
|
||||
final SelfUniqueAddress node = DistributedData.get(system).selfUniqueAddress();
|
||||
final LWWRegister<String> r1 = LWWRegister.create(node, "Hello");
|
||||
final LWWRegister<String> r2 = r1.withValue(node, "Hi");
|
||||
System.out.println(r1.value() + " by " + r1.updatedBy() + " at " + r1.timestamp());
|
||||
//#lwwregister
|
||||
// #lwwregister
|
||||
assertEquals("Hi", r2.value());
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
//#lwwregister-custom-clock
|
||||
// #lwwregister-custom-clock
|
||||
class Record {
|
||||
public final int version;
|
||||
public final String name;
|
||||
|
|
@ -392,19 +440,20 @@ public class DistributedDataDocTest extends AbstractJavaTest {
|
|||
this.address = address;
|
||||
}
|
||||
}
|
||||
|
||||
//#lwwregister-custom-clock
|
||||
|
||||
|
||||
// #lwwregister-custom-clock
|
||||
|
||||
public void demonstrateLWWRegisterWithCustomClock() {
|
||||
//#lwwregister-custom-clock
|
||||
// #lwwregister-custom-clock
|
||||
|
||||
final SelfUniqueAddress node = DistributedData.get(system).selfUniqueAddress();
|
||||
final LWWRegister.Clock<Record> recordClock = new LWWRegister.Clock<Record>() {
|
||||
@Override
|
||||
public long apply(long currentTimestamp, Record value) {
|
||||
return value.version;
|
||||
}
|
||||
};
|
||||
final LWWRegister.Clock<Record> recordClock =
|
||||
new LWWRegister.Clock<Record>() {
|
||||
@Override
|
||||
public long apply(long currentTimestamp, Record value) {
|
||||
return value.version;
|
||||
}
|
||||
};
|
||||
|
||||
final Record record1 = new Record(1, "Alice", "Union Square");
|
||||
final LWWRegister<Record> r1 = LWWRegister.create(node, record1);
|
||||
|
|
@ -414,9 +463,8 @@ public class DistributedDataDocTest extends AbstractJavaTest {
|
|||
|
||||
final LWWRegister<Record> r3 = r1.merge(r2);
|
||||
System.out.println(r3.value());
|
||||
//#lwwregister-custom-clock
|
||||
// #lwwregister-custom-clock
|
||||
|
||||
assertEquals("Madison Square", r3.value().address);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,12 +30,10 @@ import akka.cluster.ddata.Replicator.WriteMajority;
|
|||
@SuppressWarnings("unchecked")
|
||||
public class ShoppingCart extends AbstractActor {
|
||||
|
||||
//#read-write-majority
|
||||
private final WriteConsistency writeMajority =
|
||||
new WriteMajority(Duration.ofSeconds(3));
|
||||
private final static ReadConsistency readMajority =
|
||||
new ReadMajority(Duration.ofSeconds(3));
|
||||
//#read-write-majority
|
||||
// #read-write-majority
|
||||
private final WriteConsistency writeMajority = new WriteMajority(Duration.ofSeconds(3));
|
||||
private static final ReadConsistency readMajority = new ReadMajority(Duration.ofSeconds(3));
|
||||
// #read-write-majority
|
||||
|
||||
public static final String GET_CART = "getCart";
|
||||
|
||||
|
|
@ -87,33 +85,30 @@ public class ShoppingCart extends AbstractActor {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
LineItem other = (LineItem) obj;
|
||||
if (productId == null) {
|
||||
if (other.productId != null)
|
||||
return false;
|
||||
} else if (!productId.equals(other.productId))
|
||||
return false;
|
||||
if (quantity != other.quantity)
|
||||
return false;
|
||||
if (other.productId != null) return false;
|
||||
} else if (!productId.equals(other.productId)) return false;
|
||||
if (quantity != other.quantity) return false;
|
||||
if (title == null) {
|
||||
if (other.title != null)
|
||||
return false;
|
||||
} else if (!title.equals(other.title))
|
||||
return false;
|
||||
if (other.title != null) return false;
|
||||
} else if (!title.equals(other.title)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LineItem [productId=" + productId + ", title=" + title + ", quantity=" + quantity + "]";
|
||||
return "LineItem [productId="
|
||||
+ productId
|
||||
+ ", title="
|
||||
+ title
|
||||
+ ", quantity="
|
||||
+ quantity
|
||||
+ "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Props props(String userId) {
|
||||
|
|
@ -121,10 +116,12 @@ public class ShoppingCart extends AbstractActor {
|
|||
}
|
||||
|
||||
private final ActorRef replicator = DistributedData.get(getContext().getSystem()).replicator();
|
||||
private final SelfUniqueAddress node = DistributedData.get(getContext().getSystem()).selfUniqueAddress();
|
||||
private final SelfUniqueAddress node =
|
||||
DistributedData.get(getContext().getSystem()).selfUniqueAddress();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final String userId;
|
||||
|
||||
private final Key<LWWMap<String, LineItem>> dataKey;
|
||||
|
||||
public ShoppingCart(String userId) {
|
||||
|
|
@ -134,34 +131,37 @@ public class ShoppingCart extends AbstractActor {
|
|||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return matchGetCart()
|
||||
.orElse(matchAddItem())
|
||||
.orElse(matchRemoveItem())
|
||||
.orElse(matchOther());
|
||||
return matchGetCart().orElse(matchAddItem()).orElse(matchRemoveItem()).orElse(matchOther());
|
||||
}
|
||||
|
||||
//#get-cart
|
||||
// #get-cart
|
||||
private Receive matchGetCart() {
|
||||
return receiveBuilder()
|
||||
.matchEquals(GET_CART, s -> receiveGetCart())
|
||||
.match(GetSuccess.class, this::isResponseToGetCart,
|
||||
g -> receiveGetSuccess((GetSuccess<LWWMap<String, LineItem>>) g))
|
||||
.match(NotFound.class, this::isResponseToGetCart,
|
||||
n -> receiveNotFound((NotFound<LWWMap<String, LineItem>>) n))
|
||||
.match(GetFailure.class, this::isResponseToGetCart,
|
||||
f -> receiveGetFailure((GetFailure<LWWMap<String, LineItem>>) f))
|
||||
.build();
|
||||
.matchEquals(GET_CART, s -> receiveGetCart())
|
||||
.match(
|
||||
GetSuccess.class,
|
||||
this::isResponseToGetCart,
|
||||
g -> receiveGetSuccess((GetSuccess<LWWMap<String, LineItem>>) g))
|
||||
.match(
|
||||
NotFound.class,
|
||||
this::isResponseToGetCart,
|
||||
n -> receiveNotFound((NotFound<LWWMap<String, LineItem>>) n))
|
||||
.match(
|
||||
GetFailure.class,
|
||||
this::isResponseToGetCart,
|
||||
f -> receiveGetFailure((GetFailure<LWWMap<String, LineItem>>) f))
|
||||
.build();
|
||||
}
|
||||
|
||||
private void receiveGetCart() {
|
||||
Optional<Object> ctx = Optional.of(getSender());
|
||||
replicator.tell(new Replicator.Get<LWWMap<String, LineItem>>(dataKey, readMajority, ctx),
|
||||
getSelf());
|
||||
replicator.tell(
|
||||
new Replicator.Get<LWWMap<String, LineItem>>(dataKey, readMajority, ctx), getSelf());
|
||||
}
|
||||
|
||||
private boolean isResponseToGetCart(GetResponse<?> response) {
|
||||
return response.key().equals(dataKey) &&
|
||||
(response.getRequest().orElse(null) instanceof ActorRef);
|
||||
return response.key().equals(dataKey)
|
||||
&& (response.getRequest().orElse(null) instanceof ActorRef);
|
||||
}
|
||||
|
||||
private void receiveGetSuccess(GetSuccess<LWWMap<String, LineItem>> g) {
|
||||
|
|
@ -178,25 +178,24 @@ public class ShoppingCart extends AbstractActor {
|
|||
private void receiveGetFailure(GetFailure<LWWMap<String, LineItem>> f) {
|
||||
// ReadMajority failure, try again with local read
|
||||
Optional<Object> ctx = Optional.of(getSender());
|
||||
replicator.tell(new Replicator.Get<LWWMap<String, LineItem>>(dataKey, Replicator.readLocal(),
|
||||
ctx), getSelf());
|
||||
replicator.tell(
|
||||
new Replicator.Get<LWWMap<String, LineItem>>(dataKey, Replicator.readLocal(), ctx),
|
||||
getSelf());
|
||||
}
|
||||
//#get-cart
|
||||
// #get-cart
|
||||
|
||||
//#add-item
|
||||
// #add-item
|
||||
private Receive matchAddItem() {
|
||||
return receiveBuilder()
|
||||
.match(AddItem.class, this::receiveAddItem)
|
||||
.build();
|
||||
return receiveBuilder().match(AddItem.class, this::receiveAddItem).build();
|
||||
}
|
||||
|
||||
private void receiveAddItem(AddItem add) {
|
||||
Update<LWWMap<String, LineItem>> update = new Update<>(dataKey, LWWMap.create(), writeMajority,
|
||||
cart -> updateCart(cart, add.item));
|
||||
Update<LWWMap<String, LineItem>> update =
|
||||
new Update<>(dataKey, LWWMap.create(), writeMajority, cart -> updateCart(cart, add.item));
|
||||
replicator.tell(update, getSelf());
|
||||
}
|
||||
|
||||
//#add-item
|
||||
// #add-item
|
||||
|
||||
private LWWMap<String, LineItem> updateCart(LWWMap<String, LineItem> data, LineItem item) {
|
||||
if (data.contains(item.productId)) {
|
||||
|
|
@ -211,22 +210,31 @@ public class ShoppingCart extends AbstractActor {
|
|||
|
||||
private Receive matchRemoveItem() {
|
||||
return receiveBuilder()
|
||||
.match(RemoveItem.class, this::receiveRemoveItem)
|
||||
.match(GetSuccess.class, this::isResponseToRemoveItem,
|
||||
g -> receiveRemoveItemGetSuccess((GetSuccess<LWWMap<String, LineItem>>) g))
|
||||
.match(GetFailure.class, this::isResponseToRemoveItem,
|
||||
f -> receiveRemoveItemGetFailure((GetFailure<LWWMap<String, LineItem>>) f))
|
||||
.match(NotFound.class, this::isResponseToRemoveItem, n -> {/* nothing to remove */})
|
||||
.build();
|
||||
.match(RemoveItem.class, this::receiveRemoveItem)
|
||||
.match(
|
||||
GetSuccess.class,
|
||||
this::isResponseToRemoveItem,
|
||||
g -> receiveRemoveItemGetSuccess((GetSuccess<LWWMap<String, LineItem>>) g))
|
||||
.match(
|
||||
GetFailure.class,
|
||||
this::isResponseToRemoveItem,
|
||||
f -> receiveRemoveItemGetFailure((GetFailure<LWWMap<String, LineItem>>) f))
|
||||
.match(
|
||||
NotFound.class,
|
||||
this::isResponseToRemoveItem,
|
||||
n -> {
|
||||
/* nothing to remove */
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
//#remove-item
|
||||
// #remove-item
|
||||
private void receiveRemoveItem(RemoveItem rm) {
|
||||
// Try to fetch latest from a majority of nodes first, since ORMap
|
||||
// remove must have seen the item to be able to remove it.
|
||||
Optional<Object> ctx = Optional.of(rm);
|
||||
replicator.tell(new Replicator.Get<LWWMap<String, LineItem>>(dataKey, readMajority, ctx),
|
||||
getSelf());
|
||||
replicator.tell(
|
||||
new Replicator.Get<LWWMap<String, LineItem>>(dataKey, readMajority, ctx), getSelf());
|
||||
}
|
||||
|
||||
private void receiveRemoveItemGetSuccess(GetSuccess<LWWMap<String, LineItem>> g) {
|
||||
|
|
@ -234,7 +242,6 @@ public class ShoppingCart extends AbstractActor {
|
|||
removeItem(rm.productId);
|
||||
}
|
||||
|
||||
|
||||
private void receiveRemoveItemGetFailure(GetFailure<LWWMap<String, LineItem>> f) {
|
||||
// ReadMajority failed, fall back to best effort local value
|
||||
RemoveItem rm = (RemoveItem) f.getRequest().get();
|
||||
|
|
@ -242,29 +249,34 @@ public class ShoppingCart extends AbstractActor {
|
|||
}
|
||||
|
||||
private void removeItem(String productId) {
|
||||
Update<LWWMap<String, LineItem>> update = new Update<>(dataKey, LWWMap.create(), writeMajority,
|
||||
cart -> cart.remove(node, productId));
|
||||
Update<LWWMap<String, LineItem>> update =
|
||||
new Update<>(dataKey, LWWMap.create(), writeMajority, cart -> cart.remove(node, productId));
|
||||
replicator.tell(update, getSelf());
|
||||
}
|
||||
|
||||
private boolean isResponseToRemoveItem(GetResponse<?> response) {
|
||||
return response.key().equals(dataKey) &&
|
||||
(response.getRequest().orElse(null) instanceof RemoveItem);
|
||||
return response.key().equals(dataKey)
|
||||
&& (response.getRequest().orElse(null) instanceof RemoveItem);
|
||||
}
|
||||
//#remove-item
|
||||
// #remove-item
|
||||
|
||||
private Receive matchOther() {
|
||||
return receiveBuilder()
|
||||
.match(UpdateSuccess.class, u -> {
|
||||
// ok
|
||||
})
|
||||
.match(UpdateTimeout.class, t -> {
|
||||
// will eventually be replicated
|
||||
})
|
||||
.match(UpdateFailure.class, f -> {
|
||||
throw new IllegalStateException("Unexpected failure: " + f);
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
UpdateSuccess.class,
|
||||
u -> {
|
||||
// ok
|
||||
})
|
||||
.match(
|
||||
UpdateTimeout.class,
|
||||
t -> {
|
||||
// will eventually be replicated
|
||||
})
|
||||
.match(
|
||||
UpdateFailure.class,
|
||||
f -> {
|
||||
throw new IllegalStateException("Unexpected failure: " + f);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,17 +11,17 @@ import java.util.Set;
|
|||
import akka.cluster.ddata.AbstractReplicatedData;
|
||||
import akka.cluster.ddata.GSet;
|
||||
|
||||
//#twophaseset
|
||||
// #twophaseset
|
||||
public class TwoPhaseSet extends AbstractReplicatedData<TwoPhaseSet> {
|
||||
|
||||
|
||||
public final GSet<String> adds;
|
||||
public final GSet<String> removals;
|
||||
|
||||
|
||||
public TwoPhaseSet(GSet<String> adds, GSet<String> removals) {
|
||||
this.adds = adds;
|
||||
this.removals = removals;
|
||||
}
|
||||
|
||||
|
||||
public static TwoPhaseSet create() {
|
||||
return new TwoPhaseSet(GSet.create(), GSet.create());
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ public class TwoPhaseSet extends AbstractReplicatedData<TwoPhaseSet> {
|
|||
public TwoPhaseSet add(String element) {
|
||||
return new TwoPhaseSet(adds.add(element), removals);
|
||||
}
|
||||
|
||||
|
||||
public TwoPhaseSet remove(String element) {
|
||||
return new TwoPhaseSet(adds, removals.add(element));
|
||||
}
|
||||
|
|
@ -42,8 +42,7 @@ public class TwoPhaseSet extends AbstractReplicatedData<TwoPhaseSet> {
|
|||
|
||||
@Override
|
||||
public TwoPhaseSet mergeData(TwoPhaseSet that) {
|
||||
return new TwoPhaseSet(this.adds.merge(that.adds),
|
||||
this.removals.merge(that.removals));
|
||||
return new TwoPhaseSet(this.adds.merge(that.adds), this.removals.merge(that.removals));
|
||||
}
|
||||
}
|
||||
//#twophaseset
|
||||
// #twophaseset
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package jdocs.ddata.protobuf;
|
||||
|
||||
//#serializer
|
||||
// #serializer
|
||||
import jdocs.ddata.TwoPhaseSet;
|
||||
import docs.ddata.protobuf.msg.TwoPhaseSetMessages;
|
||||
import docs.ddata.protobuf.msg.TwoPhaseSetMessages.TwoPhaseSet.Builder;
|
||||
|
|
@ -16,13 +16,13 @@ import akka.cluster.ddata.GSet;
|
|||
import akka.cluster.ddata.protobuf.AbstractSerializationSupport;
|
||||
|
||||
public class TwoPhaseSetSerializer extends AbstractSerializationSupport {
|
||||
|
||||
|
||||
private final ExtendedActorSystem system;
|
||||
|
||||
public TwoPhaseSetSerializer(ExtendedActorSystem system) {
|
||||
this.system = system;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ExtendedActorSystem system() {
|
||||
return this.system;
|
||||
|
|
@ -33,7 +33,7 @@ public class TwoPhaseSetSerializer extends AbstractSerializationSupport {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public int identifier() {
|
||||
return 99998;
|
||||
}
|
||||
|
|
@ -43,8 +43,7 @@ public class TwoPhaseSetSerializer extends AbstractSerializationSupport {
|
|||
if (obj instanceof TwoPhaseSet) {
|
||||
return twoPhaseSetToProto((TwoPhaseSet) obj).toByteArray();
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't serialize object of type " + obj.getClass());
|
||||
throw new IllegalArgumentException("Can't serialize object of type " + obj.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,9 +68,8 @@ public class TwoPhaseSetSerializer extends AbstractSerializationSupport {
|
|||
}
|
||||
|
||||
protected TwoPhaseSet twoPhaseSetFromBinary(byte[] bytes) {
|
||||
try {
|
||||
TwoPhaseSetMessages.TwoPhaseSet msg =
|
||||
TwoPhaseSetMessages.TwoPhaseSet.parseFrom(bytes);
|
||||
try {
|
||||
TwoPhaseSetMessages.TwoPhaseSet msg = TwoPhaseSetMessages.TwoPhaseSet.parseFrom(bytes);
|
||||
GSet<String> adds = GSet.create();
|
||||
for (String elem : msg.getAddsList()) {
|
||||
adds = adds.add(elem);
|
||||
|
|
@ -88,6 +86,4 @@ public class TwoPhaseSetSerializer extends AbstractSerializationSupport {
|
|||
}
|
||||
}
|
||||
}
|
||||
//#serializer
|
||||
|
||||
|
||||
// #serializer
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package jdocs.ddata.protobuf;
|
||||
|
||||
//#serializer
|
||||
// #serializer
|
||||
import jdocs.ddata.TwoPhaseSet;
|
||||
import docs.ddata.protobuf.msg.TwoPhaseSetMessages;
|
||||
import docs.ddata.protobuf.msg.TwoPhaseSetMessages.TwoPhaseSet2.Builder;
|
||||
|
|
@ -15,7 +15,7 @@ import akka.cluster.ddata.protobuf.AbstractSerializationSupport;
|
|||
import akka.cluster.ddata.protobuf.ReplicatedDataSerializer;
|
||||
|
||||
public class TwoPhaseSetSerializer2 extends AbstractSerializationSupport {
|
||||
|
||||
|
||||
private final ExtendedActorSystem system;
|
||||
private final ReplicatedDataSerializer replicatedDataSerializer;
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ public class TwoPhaseSetSerializer2 extends AbstractSerializationSupport {
|
|||
this.system = system;
|
||||
this.replicatedDataSerializer = new ReplicatedDataSerializer(system);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ExtendedActorSystem system() {
|
||||
return this.system;
|
||||
|
|
@ -34,7 +34,7 @@ public class TwoPhaseSetSerializer2 extends AbstractSerializationSupport {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public int identifier() {
|
||||
return 99998;
|
||||
}
|
||||
|
|
@ -44,8 +44,7 @@ public class TwoPhaseSetSerializer2 extends AbstractSerializationSupport {
|
|||
if (obj instanceof TwoPhaseSet) {
|
||||
return twoPhaseSetToProto((TwoPhaseSet) obj).toByteArray();
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't serialize object of type " + obj.getClass());
|
||||
throw new IllegalArgumentException("Can't serialize object of type " + obj.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,24 +64,20 @@ public class TwoPhaseSetSerializer2 extends AbstractSerializationSupport {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected TwoPhaseSet twoPhaseSetFromBinary(byte[] bytes) {
|
||||
try {
|
||||
TwoPhaseSetMessages.TwoPhaseSet2 msg =
|
||||
TwoPhaseSetMessages.TwoPhaseSet2.parseFrom(bytes);
|
||||
|
||||
try {
|
||||
TwoPhaseSetMessages.TwoPhaseSet2 msg = TwoPhaseSetMessages.TwoPhaseSet2.parseFrom(bytes);
|
||||
|
||||
GSet<String> adds = GSet.create();
|
||||
if (msg.hasAdds())
|
||||
adds = (GSet<String>) otherMessageFromBinary(msg.getAdds().toByteArray());
|
||||
|
||||
if (msg.hasAdds()) adds = (GSet<String>) otherMessageFromBinary(msg.getAdds().toByteArray());
|
||||
|
||||
GSet<String> removals = GSet.create();
|
||||
if (msg.hasRemovals())
|
||||
adds = (GSet<String>) otherMessageFromBinary(msg.getRemovals().toByteArray());
|
||||
|
||||
|
||||
return new TwoPhaseSet(adds, removals);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
//#serializer
|
||||
|
||||
|
||||
// #serializer
|
||||
|
|
|
|||
|
|
@ -12,15 +12,14 @@ public class TwoPhaseSetSerializerWithCompression extends TwoPhaseSetSerializer
|
|||
public TwoPhaseSetSerializerWithCompression(ExtendedActorSystem system) {
|
||||
super(system);
|
||||
}
|
||||
|
||||
//#compression
|
||||
|
||||
// #compression
|
||||
@Override
|
||||
public byte[] toBinary(Object obj) {
|
||||
if (obj instanceof TwoPhaseSet) {
|
||||
return compress(twoPhaseSetToProto((TwoPhaseSet) obj));
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't serialize object of type " + obj.getClass());
|
||||
throw new IllegalArgumentException("Can't serialize object of type " + obj.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -28,6 +27,5 @@ public class TwoPhaseSetSerializerWithCompression extends TwoPhaseSetSerializer
|
|||
public Object fromBinaryJava(byte[] bytes, Class<?> manifest) {
|
||||
return twoPhaseSetFromBinary(decompress(bytes));
|
||||
}
|
||||
//#compression
|
||||
// #compression
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,137 +17,143 @@ import org.junit.ClassRule;
|
|||
import org.junit.Test;
|
||||
import scala.concurrent.ExecutionContext;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
import akka.actor.*;
|
||||
//#imports
|
||||
//#imports-prio
|
||||
// #imports
|
||||
// #imports-prio
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
|
||||
//#imports-prio
|
||||
// #imports-prio
|
||||
|
||||
//#imports-prio-mailbox
|
||||
// #imports-prio-mailbox
|
||||
import akka.dispatch.PriorityGenerator;
|
||||
import akka.dispatch.UnboundedStablePriorityMailbox;
|
||||
import akka.testkit.AkkaJUnitActorSystemResource;
|
||||
import com.typesafe.config.Config;
|
||||
|
||||
//#imports-prio-mailbox
|
||||
// #imports-prio-mailbox
|
||||
|
||||
//#imports-required-mailbox
|
||||
// #imports-required-mailbox
|
||||
|
||||
//#imports-required-mailbox
|
||||
// #imports-required-mailbox
|
||||
|
||||
public class DispatcherDocTest extends AbstractJavaTest {
|
||||
|
||||
@ClassRule
|
||||
public static AkkaJUnitActorSystemResource actorSystemResource =
|
||||
new AkkaJUnitActorSystemResource("DispatcherDocTest", ConfigFactory.parseString(
|
||||
DispatcherDocSpec.javaConfig()).withFallback(ConfigFactory.parseString(
|
||||
DispatcherDocSpec.config())).withFallback(AkkaSpec.testConf()));
|
||||
new AkkaJUnitActorSystemResource(
|
||||
"DispatcherDocTest",
|
||||
ConfigFactory.parseString(DispatcherDocSpec.javaConfig())
|
||||
.withFallback(ConfigFactory.parseString(DispatcherDocSpec.config()))
|
||||
.withFallback(AkkaSpec.testConf()));
|
||||
|
||||
private final ActorSystem system = actorSystemResource.getSystem();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void defineDispatcherInConfig() {
|
||||
//#defining-dispatcher-in-config
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(MyActor.class),
|
||||
"myactor");
|
||||
//#defining-dispatcher-in-config
|
||||
// #defining-dispatcher-in-config
|
||||
ActorRef myActor = system.actorOf(Props.create(MyActor.class), "myactor");
|
||||
// #defining-dispatcher-in-config
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void defineDispatcherInCode() {
|
||||
//#defining-dispatcher-in-code
|
||||
// #defining-dispatcher-in-code
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(MyActor.class).withDispatcher("my-dispatcher"),
|
||||
"myactor3");
|
||||
//#defining-dispatcher-in-code
|
||||
system.actorOf(Props.create(MyActor.class).withDispatcher("my-dispatcher"), "myactor3");
|
||||
// #defining-dispatcher-in-code
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void defineFixedPoolSizeDispatcher() {
|
||||
//#defining-fixed-pool-size-dispatcher
|
||||
ActorRef myActor = system.actorOf(Props.create(MyActor.class)
|
||||
.withDispatcher("blocking-io-dispatcher"));
|
||||
//#defining-fixed-pool-size-dispatcher
|
||||
// #defining-fixed-pool-size-dispatcher
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(MyActor.class).withDispatcher("blocking-io-dispatcher"));
|
||||
// #defining-fixed-pool-size-dispatcher
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void definePinnedDispatcher() {
|
||||
//#defining-pinned-dispatcher
|
||||
ActorRef myActor = system.actorOf(Props.create(MyActor.class)
|
||||
.withDispatcher("my-pinned-dispatcher"));
|
||||
//#defining-pinned-dispatcher
|
||||
// #defining-pinned-dispatcher
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(MyActor.class).withDispatcher("my-pinned-dispatcher"));
|
||||
// #defining-pinned-dispatcher
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void compileLookup() {
|
||||
//#lookup
|
||||
// #lookup
|
||||
// this is scala.concurrent.ExecutionContext
|
||||
// for use with Futures, Scheduler, etc.
|
||||
final ExecutionContext ex = system.dispatchers().lookup("my-dispatcher");
|
||||
//#lookup
|
||||
// #lookup
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void defineMailboxInConfig() {
|
||||
//#defining-mailbox-in-config
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(MyActor.class),
|
||||
"priomailboxactor");
|
||||
//#defining-mailbox-in-config
|
||||
// #defining-mailbox-in-config
|
||||
ActorRef myActor = system.actorOf(Props.create(MyActor.class), "priomailboxactor");
|
||||
// #defining-mailbox-in-config
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void defineMailboxInCode() {
|
||||
//#defining-mailbox-in-code
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(MyActor.class)
|
||||
.withMailbox("prio-mailbox"));
|
||||
//#defining-mailbox-in-code
|
||||
// #defining-mailbox-in-code
|
||||
ActorRef myActor = system.actorOf(Props.create(MyActor.class).withMailbox("prio-mailbox"));
|
||||
// #defining-mailbox-in-code
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void usingARequiredMailbox() {
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(MyBoundedActor.class));
|
||||
ActorRef myActor = system.actorOf(Props.create(MyBoundedActor.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void priorityDispatcher() throws Exception {
|
||||
TestKit probe = new TestKit(system);
|
||||
//#prio-dispatcher
|
||||
// #prio-dispatcher
|
||||
|
||||
class Demo extends AbstractActor {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
{
|
||||
for (Object msg : new Object[] { "lowpriority", "lowpriority",
|
||||
"highpriority", "pigdog", "pigdog2", "pigdog3", "highpriority",
|
||||
PoisonPill.getInstance() }) {
|
||||
getSelf().tell(msg, getSelf());
|
||||
for (Object msg :
|
||||
new Object[] {
|
||||
"lowpriority",
|
||||
"lowpriority",
|
||||
"highpriority",
|
||||
"pigdog",
|
||||
"pigdog2",
|
||||
"pigdog3",
|
||||
"highpriority",
|
||||
PoisonPill.getInstance()
|
||||
}) {
|
||||
getSelf().tell(msg, getSelf());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder().matchAny(message -> {
|
||||
log.info(message.toString());
|
||||
}).build();
|
||||
return receiveBuilder()
|
||||
.matchAny(
|
||||
message -> {
|
||||
log.info(message.toString());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
// We create a new Actor that just prints out what it processes
|
||||
ActorRef myActor = system.actorOf(Props.create(Demo.class, this)
|
||||
.withDispatcher("prio-dispatcher"));
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(Demo.class, this).withDispatcher("prio-dispatcher"));
|
||||
|
||||
/*
|
||||
Logs:
|
||||
|
|
@ -159,7 +165,7 @@ public class DispatcherDocTest extends AbstractJavaTest {
|
|||
'lowpriority
|
||||
'lowpriority
|
||||
*/
|
||||
//#prio-dispatcher
|
||||
// #prio-dispatcher
|
||||
|
||||
probe.watch(myActor);
|
||||
probe.expectMsgClass(Terminated.class);
|
||||
|
|
@ -168,28 +174,32 @@ public class DispatcherDocTest extends AbstractJavaTest {
|
|||
@Test
|
||||
public void controlAwareDispatcher() throws Exception {
|
||||
TestKit probe = new TestKit(system);
|
||||
//#control-aware-dispatcher
|
||||
// #control-aware-dispatcher
|
||||
|
||||
class Demo extends AbstractActor {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
{
|
||||
for (Object msg : new Object[] { "foo", "bar", new MyControlMessage(),
|
||||
PoisonPill.getInstance() }) {
|
||||
getSelf().tell(msg, getSelf());
|
||||
for (Object msg :
|
||||
new Object[] {"foo", "bar", new MyControlMessage(), PoisonPill.getInstance()}) {
|
||||
getSelf().tell(msg, getSelf());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder().matchAny(message -> {
|
||||
log.info(message.toString());
|
||||
}).build();
|
||||
return receiveBuilder()
|
||||
.matchAny(
|
||||
message -> {
|
||||
log.info(message.toString());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
// We create a new Actor that just prints out what it processes
|
||||
ActorRef myActor = system.actorOf(Props.create(Demo.class, this)
|
||||
.withDispatcher("control-aware-dispatcher"));
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(Demo.class, this).withDispatcher("control-aware-dispatcher"));
|
||||
|
||||
/*
|
||||
Logs:
|
||||
|
|
@ -197,63 +207,62 @@ public class DispatcherDocTest extends AbstractJavaTest {
|
|||
'foo
|
||||
'bar
|
||||
*/
|
||||
//#control-aware-dispatcher
|
||||
// #control-aware-dispatcher
|
||||
|
||||
probe.watch(myActor);
|
||||
probe.expectMsgClass(Terminated.class);
|
||||
}
|
||||
|
||||
static
|
||||
//#prio-mailbox
|
||||
public class MyPrioMailbox extends UnboundedStablePriorityMailbox {
|
||||
public
|
||||
// #prio-mailbox
|
||||
static class MyPrioMailbox extends UnboundedStablePriorityMailbox {
|
||||
// needed for reflective instantiation
|
||||
public MyPrioMailbox(ActorSystem.Settings settings, Config config) {
|
||||
// Create a new PriorityGenerator, lower prio means more important
|
||||
super(new PriorityGenerator() {
|
||||
@Override
|
||||
public int gen(Object message) {
|
||||
if (message.equals("highpriority"))
|
||||
return 0; // 'highpriority messages should be treated first if possible
|
||||
else if (message.equals("lowpriority"))
|
||||
return 2; // 'lowpriority messages should be treated last if possible
|
||||
else if (message.equals(PoisonPill.getInstance()))
|
||||
return 3; // PoisonPill when no other left
|
||||
else
|
||||
return 1; // By default they go between high and low prio
|
||||
}
|
||||
});
|
||||
super(
|
||||
new PriorityGenerator() {
|
||||
@Override
|
||||
public int gen(Object message) {
|
||||
if (message.equals("highpriority"))
|
||||
return 0; // 'highpriority messages should be treated first if possible
|
||||
else if (message.equals("lowpriority"))
|
||||
return 2; // 'lowpriority messages should be treated last if possible
|
||||
else if (message.equals(PoisonPill.getInstance()))
|
||||
return 3; // PoisonPill when no other left
|
||||
else return 1; // By default they go between high and low prio
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
//#prio-mailbox
|
||||
// #prio-mailbox
|
||||
|
||||
static
|
||||
//#control-aware-mailbox-messages
|
||||
public class MyControlMessage implements ControlMessage {}
|
||||
//#control-aware-mailbox-messages
|
||||
public
|
||||
// #control-aware-mailbox-messages
|
||||
static class MyControlMessage implements ControlMessage {}
|
||||
// #control-aware-mailbox-messages
|
||||
|
||||
@Test
|
||||
public void requiredMailboxDispatcher() throws Exception {
|
||||
ActorRef myActor = system.actorOf(Props.create(MyActor.class)
|
||||
.withDispatcher("custom-dispatcher"));
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(MyActor.class).withDispatcher("custom-dispatcher"));
|
||||
}
|
||||
|
||||
static
|
||||
//#require-mailbox-on-actor
|
||||
public class MySpecialActor extends AbstractActor implements
|
||||
RequiresMessageQueue<MyUnboundedMessageQueueSemantics> {
|
||||
//#require-mailbox-on-actor
|
||||
public
|
||||
// #require-mailbox-on-actor
|
||||
static class MySpecialActor extends AbstractActor
|
||||
implements RequiresMessageQueue<MyUnboundedMessageQueueSemantics> {
|
||||
// #require-mailbox-on-actor
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return AbstractActor.emptyBehavior();
|
||||
}
|
||||
//#require-mailbox-on-actor
|
||||
// #require-mailbox-on-actor
|
||||
// ...
|
||||
}
|
||||
//#require-mailbox-on-actor
|
||||
// #require-mailbox-on-actor
|
||||
|
||||
@Test
|
||||
public void requiredMailboxActor() throws Exception {
|
||||
ActorRef myActor = system.actorOf(Props.create(MySpecialActor.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package jdocs.dispatcher;
|
||||
|
||||
//#mailbox-implementation-example
|
||||
// #mailbox-implementation-example
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.dispatch.Envelope;
|
||||
|
|
@ -16,24 +16,32 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
|||
import java.util.Queue;
|
||||
import scala.Option;
|
||||
|
||||
public class MyUnboundedMailbox implements MailboxType,
|
||||
ProducesMessageQueue<MyUnboundedMailbox.MyMessageQueue> {
|
||||
public class MyUnboundedMailbox
|
||||
implements MailboxType, ProducesMessageQueue<MyUnboundedMailbox.MyMessageQueue> {
|
||||
|
||||
// This is the MessageQueue implementation
|
||||
public static class MyMessageQueue implements MessageQueue,
|
||||
MyUnboundedMessageQueueSemantics {
|
||||
private final Queue<Envelope> queue =
|
||||
new ConcurrentLinkedQueue<Envelope>();
|
||||
public static class MyMessageQueue implements MessageQueue, MyUnboundedMessageQueueSemantics {
|
||||
private final Queue<Envelope> queue = new ConcurrentLinkedQueue<Envelope>();
|
||||
|
||||
// these must be implemented; queue used as example
|
||||
public void enqueue(ActorRef receiver, Envelope handle) {
|
||||
queue.offer(handle);
|
||||
}
|
||||
public Envelope dequeue() { return queue.poll(); }
|
||||
public int numberOfMessages() { return queue.size(); }
|
||||
public boolean hasMessages() { return !queue.isEmpty(); }
|
||||
|
||||
public Envelope dequeue() {
|
||||
return queue.poll();
|
||||
}
|
||||
|
||||
public int numberOfMessages() {
|
||||
return queue.size();
|
||||
}
|
||||
|
||||
public boolean hasMessages() {
|
||||
return !queue.isEmpty();
|
||||
}
|
||||
|
||||
public void cleanUp(ActorRef owner, MessageQueue deadLetters) {
|
||||
for (Envelope handle: queue) {
|
||||
for (Envelope handle : queue) {
|
||||
deadLetters.enqueue(owner, handle);
|
||||
}
|
||||
}
|
||||
|
|
@ -49,4 +57,4 @@ public class MyUnboundedMailbox implements MailboxType,
|
|||
return new MyMessageQueue();
|
||||
}
|
||||
}
|
||||
//#mailbox-implementation-example
|
||||
// #mailbox-implementation-example
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
package jdocs.dispatcher;
|
||||
|
||||
//#mailbox-marker-interface
|
||||
// #mailbox-marker-interface
|
||||
// Marker interface used for mailbox requirements mapping
|
||||
public interface MyUnboundedMessageQueueSemantics {
|
||||
}
|
||||
//#mailbox-marker-interface
|
||||
public interface MyUnboundedMessageQueueSemantics {}
|
||||
// #mailbox-marker-interface
|
||||
|
|
|
|||
|
|
@ -4,24 +4,24 @@
|
|||
|
||||
package jdocs.duration;
|
||||
|
||||
//#import
|
||||
// #import
|
||||
import scala.concurrent.duration.Duration;
|
||||
import scala.concurrent.duration.Deadline;
|
||||
//#import
|
||||
// #import
|
||||
|
||||
class Java {
|
||||
public void demo() {
|
||||
//#dsl
|
||||
// #dsl
|
||||
final Duration fivesec = Duration.create(5, "seconds");
|
||||
final Duration threemillis = Duration.create("3 millis");
|
||||
final Duration diff = fivesec.minus(threemillis);
|
||||
assert diff.lt(fivesec);
|
||||
assert Duration.Zero().lt(Duration.Inf());
|
||||
//#dsl
|
||||
//#deadline
|
||||
// #dsl
|
||||
// #deadline
|
||||
final Deadline deadline = Duration.create(10, "seconds").fromNow();
|
||||
final Duration rest = deadline.timeLeft();
|
||||
//#deadline
|
||||
// #deadline
|
||||
rest.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,79 +18,79 @@ import akka.actor.ActorRef;
|
|||
import akka.testkit.AkkaJUnitActorSystemResource;
|
||||
import akka.util.Subclassification;
|
||||
|
||||
//#lookup-bus
|
||||
// #lookup-bus
|
||||
import akka.event.japi.LookupEventBus;
|
||||
|
||||
//#lookup-bus
|
||||
// #lookup-bus
|
||||
|
||||
//#subchannel-bus
|
||||
// #subchannel-bus
|
||||
import akka.event.japi.SubchannelEventBus;
|
||||
|
||||
//#subchannel-bus
|
||||
// #subchannel-bus
|
||||
|
||||
//#scanning-bus
|
||||
// #scanning-bus
|
||||
import akka.event.japi.ScanningEventBus;
|
||||
|
||||
//#scanning-bus
|
||||
// #scanning-bus
|
||||
|
||||
//#actor-bus
|
||||
// #actor-bus
|
||||
import akka.event.japi.ManagedActorEventBus;
|
||||
|
||||
//#actor-bus
|
||||
// #actor-bus
|
||||
|
||||
public class EventBusDocTest extends AbstractJavaTest {
|
||||
|
||||
|
||||
public static class Event {}
|
||||
|
||||
public static class Subscriber {}
|
||||
|
||||
public static class Classifier {}
|
||||
|
||||
static public interface EventBusApi extends EventBus<Event, Subscriber, Classifier> {
|
||||
|
||||
public static interface EventBusApi extends EventBus<Event, Subscriber, Classifier> {
|
||||
|
||||
@Override
|
||||
//#event-bus-api
|
||||
// #event-bus-api
|
||||
/**
|
||||
* Attempts to register the subscriber to the specified Classifier
|
||||
* @return true if successful and false if not (because it was already
|
||||
* subscribed to that Classifier, or otherwise)
|
||||
*
|
||||
* @return true if successful and false if not (because it was already subscribed to that
|
||||
* Classifier, or otherwise)
|
||||
*/
|
||||
public boolean subscribe(Subscriber subscriber, Classifier to);
|
||||
|
||||
//#event-bus-api
|
||||
|
||||
// #event-bus-api
|
||||
|
||||
@Override
|
||||
//#event-bus-api
|
||||
// #event-bus-api
|
||||
/**
|
||||
* Attempts to deregister the subscriber from the specified Classifier
|
||||
* @return true if successful and false if not (because it wasn't subscribed
|
||||
* to that Classifier, or otherwise)
|
||||
*
|
||||
* @return true if successful and false if not (because it wasn't subscribed to that Classifier,
|
||||
* or otherwise)
|
||||
*/
|
||||
public boolean unsubscribe(Subscriber subscriber, Classifier from);
|
||||
|
||||
//#event-bus-api
|
||||
|
||||
@Override
|
||||
//#event-bus-api
|
||||
/**
|
||||
* Attempts to deregister the subscriber from all Classifiers it may be subscribed to
|
||||
*/
|
||||
public void unsubscribe(Subscriber subscriber);
|
||||
|
||||
//#event-bus-api
|
||||
// #event-bus-api
|
||||
|
||||
@Override
|
||||
//#event-bus-api
|
||||
/**
|
||||
* Publishes the specified Event to this bus
|
||||
*/
|
||||
// #event-bus-api
|
||||
/** Attempts to deregister the subscriber from all Classifiers it may be subscribed to */
|
||||
public void unsubscribe(Subscriber subscriber);
|
||||
|
||||
// #event-bus-api
|
||||
|
||||
@Override
|
||||
// #event-bus-api
|
||||
/** Publishes the specified Event to this bus */
|
||||
public void publish(Event event);
|
||||
|
||||
//#event-bus-api
|
||||
|
||||
|
||||
// #event-bus-api
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
//#lookup-bus
|
||||
public class MsgEnvelope {
|
||||
public
|
||||
// #lookup-bus
|
||||
static class MsgEnvelope {
|
||||
public final String topic;
|
||||
public final Object payload;
|
||||
|
||||
|
|
@ -99,121 +99,131 @@ public class EventBusDocTest extends AbstractJavaTest {
|
|||
this.payload = payload;
|
||||
}
|
||||
}
|
||||
|
||||
//#lookup-bus
|
||||
static
|
||||
//#lookup-bus
|
||||
|
||||
// #lookup-bus
|
||||
public
|
||||
// #lookup-bus
|
||||
/**
|
||||
* Publishes the payload of the MsgEnvelope when the topic of the
|
||||
* MsgEnvelope equals the String specified when subscribing.
|
||||
* Publishes the payload of the MsgEnvelope when the topic of the MsgEnvelope equals the String
|
||||
* specified when subscribing.
|
||||
*/
|
||||
public class LookupBusImpl extends LookupEventBus<MsgEnvelope, ActorRef, String> {
|
||||
static class LookupBusImpl extends LookupEventBus<MsgEnvelope, ActorRef, String> {
|
||||
|
||||
// is used for extracting the classifier from the incoming events
|
||||
@Override public String classify(MsgEnvelope event) {
|
||||
@Override
|
||||
public String classify(MsgEnvelope event) {
|
||||
return event.topic;
|
||||
}
|
||||
|
||||
// will be invoked for each event for all subscribers which registered themselves
|
||||
// for the event’s classifier
|
||||
@Override public void publish(MsgEnvelope event, ActorRef subscriber) {
|
||||
@Override
|
||||
public void publish(MsgEnvelope event, ActorRef subscriber) {
|
||||
subscriber.tell(event.payload, ActorRef.noSender());
|
||||
}
|
||||
|
||||
// must define a full order over the subscribers, expressed as expected from
|
||||
// `java.lang.Comparable.compare`
|
||||
@Override public int compareSubscribers(ActorRef a, ActorRef b) {
|
||||
@Override
|
||||
public int compareSubscribers(ActorRef a, ActorRef b) {
|
||||
return a.compareTo(b);
|
||||
}
|
||||
|
||||
// determines the initial size of the index data structure
|
||||
// used internally (i.e. the expected number of different classifiers)
|
||||
@Override public int mapSize() {
|
||||
@Override
|
||||
public int mapSize() {
|
||||
return 128;
|
||||
}
|
||||
|
||||
}
|
||||
//#lookup-bus
|
||||
|
||||
static
|
||||
//#subchannel-bus
|
||||
public class StartsWithSubclassification implements Subclassification<String> {
|
||||
@Override public boolean isEqual(String x, String y) {
|
||||
// #lookup-bus
|
||||
|
||||
public
|
||||
// #subchannel-bus
|
||||
static class StartsWithSubclassification implements Subclassification<String> {
|
||||
@Override
|
||||
public boolean isEqual(String x, String y) {
|
||||
return x.equals(y);
|
||||
}
|
||||
|
||||
@Override public boolean isSubclass(String x, String y) {
|
||||
@Override
|
||||
public boolean isSubclass(String x, String y) {
|
||||
return x.startsWith(y);
|
||||
}
|
||||
}
|
||||
|
||||
//#subchannel-bus
|
||||
|
||||
static
|
||||
//#subchannel-bus
|
||||
|
||||
// #subchannel-bus
|
||||
|
||||
public
|
||||
// #subchannel-bus
|
||||
/**
|
||||
* Publishes the payload of the MsgEnvelope when the topic of the
|
||||
* MsgEnvelope starts with the String specified when subscribing.
|
||||
* Publishes the payload of the MsgEnvelope when the topic of the MsgEnvelope starts with the
|
||||
* String specified when subscribing.
|
||||
*/
|
||||
public class SubchannelBusImpl extends SubchannelEventBus<MsgEnvelope, ActorRef, String> {
|
||||
static class SubchannelBusImpl extends SubchannelEventBus<MsgEnvelope, ActorRef, String> {
|
||||
|
||||
// Subclassification is an object providing `isEqual` and `isSubclass`
|
||||
// to be consumed by the other methods of this classifier
|
||||
@Override public Subclassification<String> subclassification() {
|
||||
@Override
|
||||
public Subclassification<String> subclassification() {
|
||||
return new StartsWithSubclassification();
|
||||
}
|
||||
|
||||
|
||||
// is used for extracting the classifier from the incoming events
|
||||
@Override public String classify(MsgEnvelope event) {
|
||||
@Override
|
||||
public String classify(MsgEnvelope event) {
|
||||
return event.topic;
|
||||
}
|
||||
|
||||
// will be invoked for each event for all subscribers which registered themselves
|
||||
// for the event’s classifier
|
||||
@Override public void publish(MsgEnvelope event, ActorRef subscriber) {
|
||||
@Override
|
||||
public void publish(MsgEnvelope event, ActorRef subscriber) {
|
||||
subscriber.tell(event.payload, ActorRef.noSender());
|
||||
}
|
||||
|
||||
}
|
||||
//#subchannel-bus
|
||||
|
||||
static
|
||||
//#scanning-bus
|
||||
// #subchannel-bus
|
||||
|
||||
public
|
||||
// #scanning-bus
|
||||
/**
|
||||
* Publishes String messages with length less than or equal to the length
|
||||
* specified when subscribing.
|
||||
* Publishes String messages with length less than or equal to the length specified when
|
||||
* subscribing.
|
||||
*/
|
||||
public class ScanningBusImpl extends ScanningEventBus<String, ActorRef, Integer> {
|
||||
static class ScanningBusImpl extends ScanningEventBus<String, ActorRef, Integer> {
|
||||
|
||||
// is needed for determining matching classifiers and storing them in an
|
||||
// ordered collection
|
||||
@Override public int compareClassifiers(Integer a, Integer b) {
|
||||
@Override
|
||||
public int compareClassifiers(Integer a, Integer b) {
|
||||
return a.compareTo(b);
|
||||
}
|
||||
|
||||
// is needed for storing subscribers in an ordered collection
|
||||
@Override public int compareSubscribers(ActorRef a, ActorRef b) {
|
||||
// is needed for storing subscribers in an ordered collection
|
||||
@Override
|
||||
public int compareSubscribers(ActorRef a, ActorRef b) {
|
||||
return a.compareTo(b);
|
||||
}
|
||||
|
||||
// determines whether a given classifier shall match a given event; it is invoked
|
||||
// for each subscription for all received events, hence the name of the classifier
|
||||
@Override public boolean matches(Integer classifier, String event) {
|
||||
@Override
|
||||
public boolean matches(Integer classifier, String event) {
|
||||
return event.length() <= classifier;
|
||||
}
|
||||
|
||||
// will be invoked for each event for all subscribers which registered themselves
|
||||
// for the event’s classifier
|
||||
@Override public void publish(String event, ActorRef subscriber) {
|
||||
@Override
|
||||
public void publish(String event, ActorRef subscriber) {
|
||||
subscriber.tell(event, ActorRef.noSender());
|
||||
}
|
||||
|
||||
}
|
||||
//#scanning-bus
|
||||
|
||||
static
|
||||
//#actor-bus
|
||||
public class Notification {
|
||||
// #scanning-bus
|
||||
|
||||
public
|
||||
// #actor-bus
|
||||
static class Notification {
|
||||
public final ActorRef ref;
|
||||
public final int id;
|
||||
|
||||
|
|
@ -222,12 +232,12 @@ public class EventBusDocTest extends AbstractJavaTest {
|
|||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
//#actor-bus
|
||||
|
||||
static
|
||||
//#actor-bus
|
||||
public class ActorBusImpl extends ManagedActorEventBus<Notification> {
|
||||
|
||||
// #actor-bus
|
||||
|
||||
public
|
||||
// #actor-bus
|
||||
static class ActorBusImpl extends ManagedActorEventBus<Notification> {
|
||||
|
||||
// the ActorSystem will be used for book-keeping operations, such as subscribers terminating
|
||||
public ActorBusImpl(ActorSystem system) {
|
||||
|
|
@ -235,91 +245,97 @@ public class EventBusDocTest extends AbstractJavaTest {
|
|||
}
|
||||
|
||||
// is used for extracting the classifier from the incoming events
|
||||
@Override public ActorRef classify(Notification event) {
|
||||
@Override
|
||||
public ActorRef classify(Notification event) {
|
||||
return event.ref;
|
||||
}
|
||||
|
||||
|
||||
// determines the initial size of the index data structure
|
||||
// used internally (i.e. the expected number of different classifiers)
|
||||
@Override public int mapSize() {
|
||||
@Override
|
||||
public int mapSize() {
|
||||
return 128;
|
||||
}
|
||||
|
||||
}
|
||||
//#actor-bus
|
||||
|
||||
// #actor-bus
|
||||
|
||||
@ClassRule
|
||||
public static AkkaJUnitActorSystemResource actorSystemResource =
|
||||
new AkkaJUnitActorSystemResource("EventBusDocTest");
|
||||
new AkkaJUnitActorSystemResource("EventBusDocTest");
|
||||
|
||||
private final ActorSystem system = actorSystemResource.getSystem();
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateLookupClassification() {
|
||||
new TestKit(system) {{
|
||||
//#lookup-bus-test
|
||||
LookupBusImpl lookupBus = new LookupBusImpl();
|
||||
lookupBus.subscribe(getTestActor(), "greetings");
|
||||
lookupBus.publish(new MsgEnvelope("time", System.currentTimeMillis()));
|
||||
lookupBus.publish(new MsgEnvelope("greetings", "hello"));
|
||||
expectMsgEquals("hello");
|
||||
//#lookup-bus-test
|
||||
}};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void demonstrateSubchannelClassification() {
|
||||
new TestKit(system) {{
|
||||
//#subchannel-bus-test
|
||||
SubchannelBusImpl subchannelBus = new SubchannelBusImpl();
|
||||
subchannelBus.subscribe(getTestActor(), "abc");
|
||||
subchannelBus.publish(new MsgEnvelope("xyzabc", "x"));
|
||||
subchannelBus.publish(new MsgEnvelope("bcdef", "b"));
|
||||
subchannelBus.publish(new MsgEnvelope("abc", "c"));
|
||||
expectMsgEquals("c");
|
||||
subchannelBus.publish(new MsgEnvelope("abcdef", "d"));
|
||||
expectMsgEquals("d");
|
||||
//#subchannel-bus-test
|
||||
}};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void demonstrateScanningClassification() {
|
||||
new TestKit(system) {{
|
||||
//#scanning-bus-test
|
||||
ScanningBusImpl scanningBus = new ScanningBusImpl();
|
||||
scanningBus.subscribe(getTestActor(), 3);
|
||||
scanningBus.publish("xyzabc");
|
||||
scanningBus.publish("ab");
|
||||
expectMsgEquals("ab");
|
||||
scanningBus.publish("abc");
|
||||
expectMsgEquals("abc");
|
||||
//#scanning-bus-test
|
||||
}};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void demonstrateManagedActorClassification() {
|
||||
//#actor-bus-test
|
||||
ActorRef observer1 = new TestKit(system).getRef();
|
||||
ActorRef observer2 = new TestKit(system).getRef();
|
||||
TestKit probe1 = new TestKit(system);
|
||||
TestKit probe2 = new TestKit(system);
|
||||
ActorRef subscriber1 = probe1.getRef();
|
||||
ActorRef subscriber2 = probe2.getRef();
|
||||
ActorBusImpl actorBus = new ActorBusImpl(system);
|
||||
actorBus.subscribe(subscriber1, observer1);
|
||||
actorBus.subscribe(subscriber2, observer1);
|
||||
actorBus.subscribe(subscriber2, observer2);
|
||||
Notification n1 = new Notification(observer1, 100);
|
||||
actorBus.publish(n1);
|
||||
probe1.expectMsgEquals(n1);
|
||||
probe2.expectMsgEquals(n1);
|
||||
Notification n2 = new Notification(observer2, 101);
|
||||
actorBus.publish(n2);
|
||||
probe2.expectMsgEquals(n2);
|
||||
probe1.expectNoMessage(Duration.ofMillis(500));
|
||||
//#actor-bus-test
|
||||
new TestKit(system) {
|
||||
{
|
||||
// #lookup-bus-test
|
||||
LookupBusImpl lookupBus = new LookupBusImpl();
|
||||
lookupBus.subscribe(getTestActor(), "greetings");
|
||||
lookupBus.publish(new MsgEnvelope("time", System.currentTimeMillis()));
|
||||
lookupBus.publish(new MsgEnvelope("greetings", "hello"));
|
||||
expectMsgEquals("hello");
|
||||
// #lookup-bus-test
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void demonstrateSubchannelClassification() {
|
||||
new TestKit(system) {
|
||||
{
|
||||
// #subchannel-bus-test
|
||||
SubchannelBusImpl subchannelBus = new SubchannelBusImpl();
|
||||
subchannelBus.subscribe(getTestActor(), "abc");
|
||||
subchannelBus.publish(new MsgEnvelope("xyzabc", "x"));
|
||||
subchannelBus.publish(new MsgEnvelope("bcdef", "b"));
|
||||
subchannelBus.publish(new MsgEnvelope("abc", "c"));
|
||||
expectMsgEquals("c");
|
||||
subchannelBus.publish(new MsgEnvelope("abcdef", "d"));
|
||||
expectMsgEquals("d");
|
||||
// #subchannel-bus-test
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void demonstrateScanningClassification() {
|
||||
new TestKit(system) {
|
||||
{
|
||||
// #scanning-bus-test
|
||||
ScanningBusImpl scanningBus = new ScanningBusImpl();
|
||||
scanningBus.subscribe(getTestActor(), 3);
|
||||
scanningBus.publish("xyzabc");
|
||||
scanningBus.publish("ab");
|
||||
expectMsgEquals("ab");
|
||||
scanningBus.publish("abc");
|
||||
expectMsgEquals("abc");
|
||||
// #scanning-bus-test
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void demonstrateManagedActorClassification() {
|
||||
// #actor-bus-test
|
||||
ActorRef observer1 = new TestKit(system).getRef();
|
||||
ActorRef observer2 = new TestKit(system).getRef();
|
||||
TestKit probe1 = new TestKit(system);
|
||||
TestKit probe2 = new TestKit(system);
|
||||
ActorRef subscriber1 = probe1.getRef();
|
||||
ActorRef subscriber2 = probe2.getRef();
|
||||
ActorBusImpl actorBus = new ActorBusImpl(system);
|
||||
actorBus.subscribe(subscriber1, observer1);
|
||||
actorBus.subscribe(subscriber2, observer1);
|
||||
actorBus.subscribe(subscriber2, observer2);
|
||||
Notification n1 = new Notification(observer1, 100);
|
||||
actorBus.publish(n1);
|
||||
probe1.expectMsgEquals(n1);
|
||||
probe2.expectMsgEquals(n1);
|
||||
Notification n2 = new Notification(observer2, 101);
|
||||
actorBus.publish(n2);
|
||||
probe2.expectMsgEquals(n2);
|
||||
probe1.expectNoMessage(Duration.ofMillis(500));
|
||||
// #actor-bus-test
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,37 +4,37 @@
|
|||
|
||||
package jdocs.event;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
import akka.actor.*;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
|
||||
//#imports-listener
|
||||
// #imports-listener
|
||||
import akka.event.Logging.InitializeLogger;
|
||||
import akka.event.Logging.Error;
|
||||
import akka.event.Logging.Warning;
|
||||
import akka.event.Logging.Info;
|
||||
import akka.event.Logging.Debug;
|
||||
|
||||
//#imports-listener
|
||||
// #imports-listener
|
||||
|
||||
import jdocs.AbstractJavaTest;
|
||||
import akka.testkit.javadsl.TestKit;
|
||||
import org.junit.Test;
|
||||
import java.util.Optional;
|
||||
|
||||
//#imports-mdc
|
||||
// #imports-mdc
|
||||
import akka.event.DiagnosticLoggingAdapter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
//#imports-mdc
|
||||
// #imports-mdc
|
||||
|
||||
//#imports-deadletter
|
||||
// #imports-deadletter
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
//#imports-deadletter
|
||||
// #imports-deadletter
|
||||
|
||||
public class LoggingDocTest extends AbstractJavaTest {
|
||||
|
||||
|
|
@ -56,25 +56,28 @@ public class LoggingDocTest extends AbstractJavaTest {
|
|||
|
||||
@Test
|
||||
public void subscribeToDeadLetters() {
|
||||
//#deadletters
|
||||
// #deadletters
|
||||
final ActorSystem system = ActorSystem.create("DeadLetters");
|
||||
final ActorRef actor = system.actorOf(Props.create(DeadLetterActor.class));
|
||||
system.getEventStream().subscribe(actor, DeadLetter.class);
|
||||
//#deadletters
|
||||
// #deadletters
|
||||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
||||
//#superclass-subscription-eventstream
|
||||
interface AllKindsOfMusic { }
|
||||
// #superclass-subscription-eventstream
|
||||
interface AllKindsOfMusic {}
|
||||
|
||||
class Jazz implements AllKindsOfMusic {
|
||||
final public String artist;
|
||||
public final String artist;
|
||||
|
||||
public Jazz(String artist) {
|
||||
this.artist = artist;
|
||||
}
|
||||
}
|
||||
|
||||
class Electronic implements AllKindsOfMusic {
|
||||
final public String artist;
|
||||
public final String artist;
|
||||
|
||||
public Electronic(String artist) {
|
||||
this.artist = artist;
|
||||
}
|
||||
|
|
@ -82,23 +85,23 @@ public class LoggingDocTest extends AbstractJavaTest {
|
|||
|
||||
static class Listener extends AbstractActor {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Jazz.class, msg ->
|
||||
System.out.printf("%s is listening to: %s%n", getSelf().path().name(), msg)
|
||||
)
|
||||
.match(Electronic.class, msg ->
|
||||
System.out.printf("%s is listening to: %s%n", getSelf().path().name(), msg)
|
||||
)
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(
|
||||
Jazz.class,
|
||||
msg -> System.out.printf("%s is listening to: %s%n", getSelf().path().name(), msg))
|
||||
.match(
|
||||
Electronic.class,
|
||||
msg -> System.out.printf("%s is listening to: %s%n", getSelf().path().name(), msg))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
//#superclass-subscription-eventstream
|
||||
// #superclass-subscription-eventstream
|
||||
|
||||
@Test
|
||||
public void subscribeBySubclassification() {
|
||||
final ActorSystem system = ActorSystem.create("DeadLetters");
|
||||
//#superclass-subscription-eventstream
|
||||
// #superclass-subscription-eventstream
|
||||
final ActorRef actor = system.actorOf(Props.create(DeadLetterActor.class));
|
||||
system.getEventStream().subscribe(actor, DeadLetter.class);
|
||||
|
||||
|
|
@ -113,7 +116,7 @@ public class LoggingDocTest extends AbstractJavaTest {
|
|||
// jazzListener and musicListener will be notified about Jazz:
|
||||
system.getEventStream().publish(new Jazz("Sonny Rollins"));
|
||||
|
||||
//#superclass-subscription-eventstream
|
||||
// #superclass-subscription-eventstream
|
||||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
||||
|
|
@ -122,20 +125,21 @@ public class LoggingDocTest extends AbstractJavaTest {
|
|||
final ActorSystem system = ActorSystem.create("SuppressedDeadLetters");
|
||||
final ActorRef actor = system.actorOf(Props.create(DeadLetterActor.class));
|
||||
|
||||
//#suppressed-deadletters
|
||||
// #suppressed-deadletters
|
||||
system.getEventStream().subscribe(actor, SuppressedDeadLetter.class);
|
||||
//#suppressed-deadletters
|
||||
// #suppressed-deadletters
|
||||
|
||||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subscribeToAllDeadLetters() {
|
||||
final ActorSystem system = ActorSystem.create("AllDeadLetters");
|
||||
final ActorRef actor = system.actorOf(Props.create(DeadLetterActor.class));
|
||||
|
||||
//#all-deadletters
|
||||
// #all-deadletters
|
||||
system.getEventStream().subscribe(actor, AllDeadLetters.class);
|
||||
//#all-deadletters
|
||||
// #all-deadletters
|
||||
|
||||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
|
@ -143,14 +147,14 @@ public class LoggingDocTest extends AbstractJavaTest {
|
|||
@Test
|
||||
public void demonstrateMultipleArgs() {
|
||||
final ActorSystem system = ActorSystem.create("multiArg");
|
||||
//#array
|
||||
final Object[] args = new Object[] { "The", "brown", "fox", "jumps", 42 };
|
||||
// #array
|
||||
final Object[] args = new Object[] {"The", "brown", "fox", "jumps", 42};
|
||||
system.log().debug("five parameters: {}, {}, {}, {}, {}", args);
|
||||
//#array
|
||||
// #array
|
||||
TestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
||||
//#my-actor
|
||||
// #my-actor
|
||||
class MyActor extends AbstractActor {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
|
|
@ -161,86 +165,98 @@ public class LoggingDocTest extends AbstractJavaTest {
|
|||
|
||||
@Override
|
||||
public void preRestart(Throwable reason, Optional<Object> message) {
|
||||
log.error(reason, "Restarting due to [{}] when processing [{}]",
|
||||
reason.getMessage(), message.isPresent() ? message.get() : "");
|
||||
log.error(
|
||||
reason,
|
||||
"Restarting due to [{}] when processing [{}]",
|
||||
reason.getMessage(),
|
||||
message.isPresent() ? message.get() : "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("test", msg ->
|
||||
log.info("Received test")
|
||||
)
|
||||
.matchAny(msg ->
|
||||
log.warning("Received unknown message: {}", msg)
|
||||
)
|
||||
.build();
|
||||
.matchEquals("test", msg -> log.info("Received test"))
|
||||
.matchAny(msg -> log.warning("Received unknown message: {}", msg))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
//#my-actor
|
||||
// #my-actor
|
||||
|
||||
//#mdc-actor
|
||||
// #mdc-actor
|
||||
class MdcActor extends AbstractActor {
|
||||
|
||||
final DiagnosticLoggingAdapter log = Logging.getLogger(this);
|
||||
final DiagnosticLoggingAdapter log = Logging.getLogger(this);
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchAny(msg -> {
|
||||
Map<String, Object> mdc;
|
||||
mdc = new HashMap<String, Object>();
|
||||
mdc.put("requestId", 1234);
|
||||
mdc.put("visitorId", 5678);
|
||||
log.setMDC(mdc);
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchAny(
|
||||
msg -> {
|
||||
Map<String, Object> mdc;
|
||||
mdc = new HashMap<String, Object>();
|
||||
mdc.put("requestId", 1234);
|
||||
mdc.put("visitorId", 5678);
|
||||
log.setMDC(mdc);
|
||||
|
||||
log.info("Starting new request");
|
||||
log.info("Starting new request");
|
||||
|
||||
log.clearMDC();
|
||||
})
|
||||
log.clearMDC();
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#mdc-actor
|
||||
// #mdc-actor
|
||||
|
||||
//#my-event-listener
|
||||
// #my-event-listener
|
||||
class MyEventListener extends AbstractActor {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(InitializeLogger.class, msg -> {
|
||||
getSender().tell(Logging.loggerInitialized(), getSelf());
|
||||
})
|
||||
.match(Error.class, msg -> {
|
||||
// ...
|
||||
})
|
||||
.match(Warning.class, msg -> {
|
||||
// ...
|
||||
})
|
||||
.match(Info.class, msg -> {
|
||||
// ...
|
||||
})
|
||||
.match(Debug.class, msg -> {
|
||||
// ...
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
InitializeLogger.class,
|
||||
msg -> {
|
||||
getSender().tell(Logging.loggerInitialized(), getSelf());
|
||||
})
|
||||
.match(
|
||||
Error.class,
|
||||
msg -> {
|
||||
// ...
|
||||
})
|
||||
.match(
|
||||
Warning.class,
|
||||
msg -> {
|
||||
// ...
|
||||
})
|
||||
.match(
|
||||
Info.class,
|
||||
msg -> {
|
||||
// ...
|
||||
})
|
||||
.match(
|
||||
Debug.class,
|
||||
msg -> {
|
||||
// ...
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#my-event-listener
|
||||
// #my-event-listener
|
||||
|
||||
static
|
||||
//#deadletter-actor
|
||||
public class DeadLetterActor extends AbstractActor {
|
||||
public
|
||||
// #deadletter-actor
|
||||
static class DeadLetterActor extends AbstractActor {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(DeadLetter.class, msg -> {
|
||||
System.out.println(msg);
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
DeadLetter.class,
|
||||
msg -> {
|
||||
System.out.println(msg);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#deadletter-actor
|
||||
// #deadletter-actor
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,87 +4,87 @@
|
|||
|
||||
package jdocs.extension;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
import akka.actor.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
|
||||
import jdocs.AbstractJavaTest;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ExtensionDocTest extends AbstractJavaTest {
|
||||
|
||||
static
|
||||
//#extension
|
||||
public class CountExtensionImpl implements Extension {
|
||||
//Since this Extension is a shared instance
|
||||
public
|
||||
// #extension
|
||||
static class CountExtensionImpl implements Extension {
|
||||
// Since this Extension is a shared instance
|
||||
// per ActorSystem we need to be threadsafe
|
||||
private final AtomicLong counter = new AtomicLong(0);
|
||||
|
||||
//This is the operation this Extension provides
|
||||
// This is the operation this Extension provides
|
||||
public long increment() {
|
||||
return counter.incrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
//#extension
|
||||
// #extension
|
||||
|
||||
static
|
||||
//#extensionid
|
||||
public class CountExtension extends AbstractExtensionId<CountExtensionImpl>
|
||||
implements ExtensionIdProvider {
|
||||
//This will be the identifier of our CountExtension
|
||||
public final static CountExtension CountExtensionProvider = new CountExtension();
|
||||
public
|
||||
// #extensionid
|
||||
static class CountExtension extends AbstractExtensionId<CountExtensionImpl>
|
||||
implements ExtensionIdProvider {
|
||||
// This will be the identifier of our CountExtension
|
||||
public static final CountExtension CountExtensionProvider = new CountExtension();
|
||||
|
||||
private CountExtension() {}
|
||||
|
||||
//The lookup method is required by ExtensionIdProvider,
|
||||
// The lookup method is required by ExtensionIdProvider,
|
||||
// so we return ourselves here, this allows us
|
||||
// to configure our extension to be loaded when
|
||||
// the ActorSystem starts up
|
||||
public CountExtension lookup() {
|
||||
return CountExtension.CountExtensionProvider; //The public static final
|
||||
return CountExtension.CountExtensionProvider; // The public static final
|
||||
}
|
||||
|
||||
//This method will be called by Akka
|
||||
// This method will be called by Akka
|
||||
// to instantiate our Extension
|
||||
public CountExtensionImpl createExtension(ExtendedActorSystem system) {
|
||||
return new CountExtensionImpl();
|
||||
}
|
||||
}
|
||||
|
||||
//#extensionid
|
||||
// #extensionid
|
||||
|
||||
static
|
||||
//#extension-usage-actor
|
||||
public class MyActor extends AbstractActor {
|
||||
public
|
||||
// #extension-usage-actor
|
||||
static class MyActor extends AbstractActor {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchAny(msg -> {
|
||||
// typically you would use static import of the
|
||||
// CountExtension.CountExtensionProvider field
|
||||
CountExtension.CountExtensionProvider.get(getContext().getSystem()).increment();
|
||||
})
|
||||
.build();
|
||||
.matchAny(
|
||||
msg -> {
|
||||
// typically you would use static import of the
|
||||
// CountExtension.CountExtensionProvider field
|
||||
CountExtension.CountExtensionProvider.get(getContext().getSystem()).increment();
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
//#extension-usage-actor
|
||||
// #extension-usage-actor
|
||||
|
||||
@Test
|
||||
public void demonstrateHowToCreateAndUseAnAkkaExtensionInJava() {
|
||||
final ActorSystem system = null;
|
||||
try {
|
||||
//#extension-usage
|
||||
// #extension-usage
|
||||
// typically you would use static import of the
|
||||
// CountExtension.CountExtensionProvider field
|
||||
CountExtension.CountExtensionProvider.get(system).increment();
|
||||
//#extension-usage
|
||||
// #extension-usage
|
||||
} catch (Exception e) {
|
||||
//do nothing
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package jdocs.extension;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
import akka.actor.Extension;
|
||||
import akka.actor.AbstractExtensionId;
|
||||
import akka.actor.ExtensionIdProvider;
|
||||
|
|
@ -14,7 +14,7 @@ import com.typesafe.config.Config;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.time.Duration;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
|
||||
import jdocs.AbstractJavaTest;
|
||||
import akka.actor.AbstractActor;
|
||||
|
|
@ -22,9 +22,9 @@ import org.junit.Test;
|
|||
|
||||
public class SettingsExtensionDocTest extends AbstractJavaTest {
|
||||
|
||||
static
|
||||
//#extension
|
||||
public class SettingsImpl implements Extension {
|
||||
public
|
||||
// #extension
|
||||
static class SettingsImpl implements Extension {
|
||||
|
||||
public final String DB_URI;
|
||||
public final Duration CIRCUIT_BREAKER_TIMEOUT;
|
||||
|
|
@ -32,18 +32,17 @@ public class SettingsExtensionDocTest extends AbstractJavaTest {
|
|||
public SettingsImpl(Config config) {
|
||||
DB_URI = config.getString("myapp.db.uri");
|
||||
CIRCUIT_BREAKER_TIMEOUT =
|
||||
Duration.ofMillis(config.getDuration("myapp.circuit-breaker.timeout", TimeUnit.MILLISECONDS));
|
||||
Duration.ofMillis(
|
||||
config.getDuration("myapp.circuit-breaker.timeout", TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//#extension
|
||||
// #extension
|
||||
|
||||
static
|
||||
//#extensionid
|
||||
public class Settings extends AbstractExtensionId<SettingsImpl>
|
||||
implements ExtensionIdProvider {
|
||||
public final static Settings SettingsProvider = new Settings();
|
||||
public
|
||||
// #extensionid
|
||||
static class Settings extends AbstractExtensionId<SettingsImpl> implements ExtensionIdProvider {
|
||||
public static final Settings SettingsProvider = new Settings();
|
||||
|
||||
private Settings() {}
|
||||
|
||||
|
|
@ -56,18 +55,16 @@ public class SettingsExtensionDocTest extends AbstractJavaTest {
|
|||
}
|
||||
}
|
||||
|
||||
//#extensionid
|
||||
// #extensionid
|
||||
|
||||
static
|
||||
//#extension-usage-actor
|
||||
public class MyActor extends AbstractActor {
|
||||
public
|
||||
// #extension-usage-actor
|
||||
static class MyActor extends AbstractActor {
|
||||
// typically you would use static import of the Settings.SettingsProvider field
|
||||
final SettingsImpl settings =
|
||||
Settings.SettingsProvider.get(getContext().getSystem());
|
||||
Connection connection =
|
||||
connect(settings.DB_URI, settings.CIRCUIT_BREAKER_TIMEOUT);
|
||||
final SettingsImpl settings = Settings.SettingsProvider.get(getContext().getSystem());
|
||||
Connection connection = connect(settings.DB_URI, settings.CIRCUIT_BREAKER_TIMEOUT);
|
||||
|
||||
//#extension-usage-actor
|
||||
// #extension-usage-actor
|
||||
|
||||
public Connection connect(String dbUri, Duration circuitBreakerTimeout) {
|
||||
return new Connection();
|
||||
|
|
@ -77,24 +74,22 @@ public class SettingsExtensionDocTest extends AbstractJavaTest {
|
|||
public Receive createReceive() {
|
||||
return AbstractActor.emptyBehavior();
|
||||
}
|
||||
//#extension-usage-actor
|
||||
// #extension-usage-actor
|
||||
}
|
||||
//#extension-usage-actor
|
||||
// #extension-usage-actor
|
||||
|
||||
public static class Connection {
|
||||
}
|
||||
public static class Connection {}
|
||||
|
||||
@Test
|
||||
public void demonstrateHowToCreateAndUseAnAkkaExtensionInJava() {
|
||||
final ActorSystem system = null;
|
||||
try {
|
||||
//#extension-usage
|
||||
// #extension-usage
|
||||
// typically you would use static import of the Settings.SettingsProvider field
|
||||
String dbUri = Settings.SettingsProvider.get(system).DB_URI;
|
||||
//#extension-usage
|
||||
// #extension-usage
|
||||
} catch (Exception e) {
|
||||
//do nothing
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@
|
|||
|
||||
package jdocs.future;
|
||||
|
||||
//#context-dispatcher
|
||||
// #context-dispatcher
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.dispatch.Futures;
|
||||
|
||||
public class ActorWithFuture extends AbstractActor {
|
||||
ActorWithFuture(){
|
||||
ActorWithFuture() {
|
||||
Futures.future(() -> "hello", getContext().dispatcher());
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -6,7 +6,7 @@ package jdocs.io;
|
|||
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.AbstractActor;
|
||||
//#imports
|
||||
// #imports
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -17,68 +17,78 @@ import akka.io.TcpMessage;
|
|||
import akka.io.TcpSO;
|
||||
import akka.util.ByteString;
|
||||
import java.time.Duration;
|
||||
//#imports
|
||||
// #imports
|
||||
|
||||
public class IODocTest {
|
||||
|
||||
static public class Demo extends AbstractActor {
|
||||
public static class Demo extends AbstractActor {
|
||||
ActorRef connectionActor = null;
|
||||
ActorRef listener = getSelf();
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("connect", msg -> {
|
||||
//#manager
|
||||
final ActorRef tcp = Tcp.get(system).manager();
|
||||
//#manager
|
||||
//#connect
|
||||
final InetSocketAddress remoteAddr = new InetSocketAddress("127.0.0.1",
|
||||
12345);
|
||||
tcp.tell(TcpMessage.connect(remoteAddr), getSelf());
|
||||
//#connect
|
||||
//#connect-with-options
|
||||
final InetSocketAddress localAddr = new InetSocketAddress("127.0.0.1",
|
||||
1234);
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
options.add(TcpSO.keepAlive(true));
|
||||
Duration timeout = null;
|
||||
tcp.tell(TcpMessage.connect(remoteAddr, localAddr, options, timeout, false), getSelf());
|
||||
//#connect-with-options
|
||||
})
|
||||
//#connected
|
||||
.match(Tcp.Connected.class, conn -> {
|
||||
connectionActor = getSender();
|
||||
connectionActor.tell(TcpMessage.register(listener), getSelf());
|
||||
})
|
||||
//#connected
|
||||
//#received
|
||||
.match(Tcp.Received.class, recv -> {
|
||||
final ByteString data = recv.data();
|
||||
// and do something with the received data ...
|
||||
})
|
||||
.match(Tcp.CommandFailed.class, failed -> {
|
||||
final Tcp.Command command = failed.cmd();
|
||||
// react to failed connect, bind, write, etc.
|
||||
})
|
||||
.match(Tcp.ConnectionClosed.class, closed -> {
|
||||
if (closed.isAborted()) {
|
||||
// handle close reasons like this
|
||||
}
|
||||
})
|
||||
//#received
|
||||
.matchEquals("bind", msg -> {
|
||||
final ActorRef handler = getSelf();
|
||||
//#bind
|
||||
final ActorRef tcp = Tcp.get(system).manager();
|
||||
final InetSocketAddress localAddr = new InetSocketAddress("127.0.0.1",
|
||||
1234);
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
options.add(TcpSO.reuseAddress(true));
|
||||
tcp.tell(TcpMessage.bind(handler, localAddr, 10, options, false), getSelf());
|
||||
//#bind
|
||||
})
|
||||
.build();
|
||||
.matchEquals(
|
||||
"connect",
|
||||
msg -> {
|
||||
// #manager
|
||||
final ActorRef tcp = Tcp.get(system).manager();
|
||||
// #manager
|
||||
// #connect
|
||||
final InetSocketAddress remoteAddr = new InetSocketAddress("127.0.0.1", 12345);
|
||||
tcp.tell(TcpMessage.connect(remoteAddr), getSelf());
|
||||
// #connect
|
||||
// #connect-with-options
|
||||
final InetSocketAddress localAddr = new InetSocketAddress("127.0.0.1", 1234);
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
options.add(TcpSO.keepAlive(true));
|
||||
Duration timeout = null;
|
||||
tcp.tell(
|
||||
TcpMessage.connect(remoteAddr, localAddr, options, timeout, false), getSelf());
|
||||
// #connect-with-options
|
||||
})
|
||||
// #connected
|
||||
.match(
|
||||
Tcp.Connected.class,
|
||||
conn -> {
|
||||
connectionActor = getSender();
|
||||
connectionActor.tell(TcpMessage.register(listener), getSelf());
|
||||
})
|
||||
// #connected
|
||||
// #received
|
||||
.match(
|
||||
Tcp.Received.class,
|
||||
recv -> {
|
||||
final ByteString data = recv.data();
|
||||
// and do something with the received data ...
|
||||
})
|
||||
.match(
|
||||
Tcp.CommandFailed.class,
|
||||
failed -> {
|
||||
final Tcp.Command command = failed.cmd();
|
||||
// react to failed connect, bind, write, etc.
|
||||
})
|
||||
.match(
|
||||
Tcp.ConnectionClosed.class,
|
||||
closed -> {
|
||||
if (closed.isAborted()) {
|
||||
// handle close reasons like this
|
||||
}
|
||||
})
|
||||
// #received
|
||||
.matchEquals(
|
||||
"bind",
|
||||
msg -> {
|
||||
final ActorRef handler = getSelf();
|
||||
// #bind
|
||||
final ActorRef tcp = Tcp.get(system).manager();
|
||||
final InetSocketAddress localAddr = new InetSocketAddress("127.0.0.1", 1234);
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
options.add(TcpSO.reuseAddress(true));
|
||||
tcp.tell(TcpMessage.bind(handler, localAddr, 10, options, false), getSelf());
|
||||
// #bind
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,87 +17,90 @@ import java.net.InetSocketAddress;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009-2018 Lightbend Inc. <https://www.lightbend.com>
|
||||
*/
|
||||
/** Copyright (C) 2009-2018 Lightbend Inc. <https://www.lightbend.com> */
|
||||
public class JavaReadBackPressure {
|
||||
|
||||
static public class Listener extends AbstractActor {
|
||||
ActorRef tcp;
|
||||
ActorRef listener;
|
||||
public static class Listener extends AbstractActor {
|
||||
ActorRef tcp;
|
||||
ActorRef listener;
|
||||
|
||||
@Override
|
||||
//#pull-accepting
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Tcp.Bound.class, x -> {
|
||||
listener = getSender();
|
||||
// Accept connections one by one
|
||||
listener.tell(TcpMessage.resumeAccepting(1), getSelf());
|
||||
})
|
||||
.match(Tcp.Connected.class, x -> {
|
||||
ActorRef handler = getContext().actorOf(Props.create(PullEcho.class, getSender()));
|
||||
getSender().tell(TcpMessage.register(handler), getSelf());
|
||||
// Resume accepting connections
|
||||
listener.tell(TcpMessage.resumeAccepting(1), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
//#pull-accepting
|
||||
@Override
|
||||
// #pull-accepting
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(
|
||||
Tcp.Bound.class,
|
||||
x -> {
|
||||
listener = getSender();
|
||||
// Accept connections one by one
|
||||
listener.tell(TcpMessage.resumeAccepting(1), getSelf());
|
||||
})
|
||||
.match(
|
||||
Tcp.Connected.class,
|
||||
x -> {
|
||||
ActorRef handler = getContext().actorOf(Props.create(PullEcho.class, getSender()));
|
||||
getSender().tell(TcpMessage.register(handler), getSelf());
|
||||
// Resume accepting connections
|
||||
listener.tell(TcpMessage.resumeAccepting(1), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
// #pull-accepting
|
||||
|
||||
@Override
|
||||
public void preStart() throws Exception {
|
||||
//#pull-mode-bind
|
||||
tcp = Tcp.get(getContext().getSystem()).manager();
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
tcp.tell(
|
||||
TcpMessage.bind(getSelf(), new InetSocketAddress("localhost", 0), 100, options, true),
|
||||
getSelf()
|
||||
);
|
||||
//#pull-mode-bind
|
||||
}
|
||||
|
||||
private void demonstrateConnect() {
|
||||
//#pull-mode-connect
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
Duration timeout = null;
|
||||
tcp.tell(
|
||||
TcpMessage.connect(new InetSocketAddress("localhost", 3000), null, options, timeout, true),
|
||||
getSelf()
|
||||
);
|
||||
//#pull-mode-connect
|
||||
}
|
||||
@Override
|
||||
public void preStart() throws Exception {
|
||||
// #pull-mode-bind
|
||||
tcp = Tcp.get(getContext().getSystem()).manager();
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
tcp.tell(
|
||||
TcpMessage.bind(getSelf(), new InetSocketAddress("localhost", 0), 100, options, true),
|
||||
getSelf());
|
||||
// #pull-mode-bind
|
||||
}
|
||||
|
||||
static public class Ack implements Tcp.Event {
|
||||
private void demonstrateConnect() {
|
||||
// #pull-mode-connect
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
Duration timeout = null;
|
||||
tcp.tell(
|
||||
TcpMessage.connect(
|
||||
new InetSocketAddress("localhost", 3000), null, options, timeout, true),
|
||||
getSelf());
|
||||
// #pull-mode-connect
|
||||
}
|
||||
}
|
||||
|
||||
public static class Ack implements Tcp.Event {}
|
||||
|
||||
public static class PullEcho extends AbstractActor {
|
||||
final ActorRef connection;
|
||||
|
||||
public PullEcho(ActorRef connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
static public class PullEcho extends AbstractActor {
|
||||
final ActorRef connection;
|
||||
|
||||
public PullEcho(ActorRef connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
//#pull-reading-echo
|
||||
@Override
|
||||
public void preStart() throws Exception {
|
||||
connection.tell(TcpMessage.resumeReading(), getSelf());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Tcp.Received.class, message -> {
|
||||
ByteString data = message.data();
|
||||
connection.tell(TcpMessage.write(data, new Ack()), getSelf());
|
||||
})
|
||||
.match(Ack.class, message -> {
|
||||
connection.tell(TcpMessage.resumeReading(), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
//#pull-reading-echo
|
||||
// #pull-reading-echo
|
||||
@Override
|
||||
public void preStart() throws Exception {
|
||||
connection.tell(TcpMessage.resumeReading(), getSelf());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(
|
||||
Tcp.Received.class,
|
||||
message -> {
|
||||
ByteString data = message.data();
|
||||
connection.tell(TcpMessage.write(data, new Ack()), getSelf());
|
||||
})
|
||||
.match(
|
||||
Ack.class,
|
||||
message -> {
|
||||
connection.tell(TcpMessage.resumeReading(), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
// #pull-reading-echo
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package jdocs.io;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.event.Logging;
|
||||
|
|
@ -22,107 +22,114 @@ import java.net.DatagramSocket;
|
|||
import java.nio.channels.DatagramChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
//#imports
|
||||
// #imports
|
||||
|
||||
public class JavaUdpMulticast {
|
||||
//#inet6-protocol-family
|
||||
public static class Inet6ProtocolFamily extends Inet.DatagramChannelCreator {
|
||||
@Override
|
||||
public DatagramChannel create() throws Exception {
|
||||
return DatagramChannel.open(StandardProtocolFamily.INET6);
|
||||
}
|
||||
// #inet6-protocol-family
|
||||
public static class Inet6ProtocolFamily extends Inet.DatagramChannelCreator {
|
||||
@Override
|
||||
public DatagramChannel create() throws Exception {
|
||||
return DatagramChannel.open(StandardProtocolFamily.INET6);
|
||||
}
|
||||
//#inet6-protocol-family
|
||||
}
|
||||
// #inet6-protocol-family
|
||||
|
||||
//#multicast-group
|
||||
public static class MulticastGroup extends Inet.AbstractSocketOptionV2 {
|
||||
private String address;
|
||||
private String interf;
|
||||
// #multicast-group
|
||||
public static class MulticastGroup extends Inet.AbstractSocketOptionV2 {
|
||||
private String address;
|
||||
private String interf;
|
||||
|
||||
public MulticastGroup(String address, String interf) {
|
||||
this.address = address;
|
||||
this.interf = interf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterBind(DatagramSocket s) {
|
||||
try {
|
||||
InetAddress group = InetAddress.getByName(address);
|
||||
NetworkInterface networkInterface = NetworkInterface.getByName(interf);
|
||||
s.getChannel().join(group, networkInterface);
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Unable to join multicast group.");
|
||||
}
|
||||
}
|
||||
}
|
||||
//#multicast-group
|
||||
|
||||
public static class Listener extends AbstractActor {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
ActorRef sink;
|
||||
|
||||
public Listener(String iface, String group, Integer port, ActorRef sink) {
|
||||
this.sink = sink;
|
||||
|
||||
//#bind
|
||||
List<Inet.SocketOption> options = new ArrayList<>();
|
||||
options.add(new Inet6ProtocolFamily());
|
||||
options.add(new MulticastGroup(group, iface));
|
||||
|
||||
final ActorRef mgr = Udp.get(getContext().getSystem()).getManager();
|
||||
// listen for datagrams on this address
|
||||
InetSocketAddress endpoint = new InetSocketAddress(port);
|
||||
mgr.tell(UdpMessage.bind(getSelf(), endpoint, options), getSelf());
|
||||
//#bind
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Udp.Bound.class, bound -> {
|
||||
log.info("Bound to {}", bound.localAddress());
|
||||
sink.tell(bound, getSelf());
|
||||
})
|
||||
.match(Udp.Received.class, received -> {
|
||||
final String txt = received.data().decodeString("utf-8");
|
||||
log.info("Received '{}' from {}", txt, received.sender());
|
||||
sink.tell(txt, getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
public MulticastGroup(String address, String interf) {
|
||||
this.address = address;
|
||||
this.interf = interf;
|
||||
}
|
||||
|
||||
public static class Sender extends AbstractActor {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
String iface;
|
||||
String group;
|
||||
Integer port;
|
||||
String message;
|
||||
|
||||
public Sender(String iface, String group, Integer port, String msg) {
|
||||
this.iface = iface;
|
||||
this.group = group;
|
||||
this.port = port;
|
||||
this.message = msg;
|
||||
|
||||
List<Inet.SocketOption> options = new ArrayList<>();
|
||||
options.add(new Inet6ProtocolFamily());
|
||||
|
||||
final ActorRef mgr = Udp.get(getContext().getSystem()).getManager();
|
||||
mgr.tell(UdpMessage.simpleSender(options), getSelf());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Udp.SimpleSenderReady.class, x -> {
|
||||
InetSocketAddress remote = new InetSocketAddress(group + "%" + iface, port);
|
||||
log.info("Sending message to " + remote);
|
||||
getSender().tell(UdpMessage.send(ByteString.fromString(message), remote), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
@Override
|
||||
public void afterBind(DatagramSocket s) {
|
||||
try {
|
||||
InetAddress group = InetAddress.getByName(address);
|
||||
NetworkInterface networkInterface = NetworkInterface.getByName(interf);
|
||||
s.getChannel().join(group, networkInterface);
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Unable to join multicast group.");
|
||||
}
|
||||
}
|
||||
}
|
||||
// #multicast-group
|
||||
|
||||
public static class Listener extends AbstractActor {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
ActorRef sink;
|
||||
|
||||
public Listener(String iface, String group, Integer port, ActorRef sink) {
|
||||
this.sink = sink;
|
||||
|
||||
// #bind
|
||||
List<Inet.SocketOption> options = new ArrayList<>();
|
||||
options.add(new Inet6ProtocolFamily());
|
||||
options.add(new MulticastGroup(group, iface));
|
||||
|
||||
final ActorRef mgr = Udp.get(getContext().getSystem()).getManager();
|
||||
// listen for datagrams on this address
|
||||
InetSocketAddress endpoint = new InetSocketAddress(port);
|
||||
mgr.tell(UdpMessage.bind(getSelf(), endpoint, options), getSelf());
|
||||
// #bind
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(
|
||||
Udp.Bound.class,
|
||||
bound -> {
|
||||
log.info("Bound to {}", bound.localAddress());
|
||||
sink.tell(bound, getSelf());
|
||||
})
|
||||
.match(
|
||||
Udp.Received.class,
|
||||
received -> {
|
||||
final String txt = received.data().decodeString("utf-8");
|
||||
log.info("Received '{}' from {}", txt, received.sender());
|
||||
sink.tell(txt, getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Sender extends AbstractActor {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
String iface;
|
||||
String group;
|
||||
Integer port;
|
||||
String message;
|
||||
|
||||
public Sender(String iface, String group, Integer port, String msg) {
|
||||
this.iface = iface;
|
||||
this.group = group;
|
||||
this.port = port;
|
||||
this.message = msg;
|
||||
|
||||
List<Inet.SocketOption> options = new ArrayList<>();
|
||||
options.add(new Inet6ProtocolFamily());
|
||||
|
||||
final ActorRef mgr = Udp.get(getContext().getSystem()).getManager();
|
||||
mgr.tell(UdpMessage.simpleSender(options), getSelf());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(
|
||||
Udp.SimpleSenderReady.class,
|
||||
x -> {
|
||||
InetSocketAddress remote = new InetSocketAddress(group + "%" + iface, port);
|
||||
log.info("Sending message to " + remote);
|
||||
getSender()
|
||||
.tell(UdpMessage.send(ByteString.fromString(message), remote), getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,80 +21,96 @@ import java.net.InetAddress;
|
|||
import java.net.NetworkInterface;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class JavaUdpMulticastTest extends AbstractJavaTest {
|
||||
|
||||
static ActorSystem system;
|
||||
static ActorSystem system;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
system = ActorSystem.create("JavaUdpMulticastTest");
|
||||
}
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
system = ActorSystem.create("JavaUdpMulticastTest");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUdpMulticast() throws Exception {
|
||||
new TestKit(system) {{
|
||||
List<NetworkInterface> ipv6Ifaces = new ArrayList<>();
|
||||
for (Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements(); ) {
|
||||
NetworkInterface interf = interfaces.nextElement();
|
||||
if (interf.isUp() && interf.supportsMulticast()) {
|
||||
for (Enumeration<InetAddress> addresses = interf.getInetAddresses(); addresses.hasMoreElements(); ) {
|
||||
InetAddress address = addresses.nextElement();
|
||||
if (address instanceof Inet6Address) {
|
||||
ipv6Ifaces.add(interf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testUdpMulticast() throws Exception {
|
||||
new TestKit(system) {
|
||||
{
|
||||
List<NetworkInterface> ipv6Ifaces = new ArrayList<>();
|
||||
for (Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
|
||||
interfaces.hasMoreElements(); ) {
|
||||
NetworkInterface interf = interfaces.nextElement();
|
||||
if (interf.isUp() && interf.supportsMulticast()) {
|
||||
for (Enumeration<InetAddress> addresses = interf.getInetAddresses();
|
||||
addresses.hasMoreElements(); ) {
|
||||
InetAddress address = addresses.nextElement();
|
||||
if (address instanceof Inet6Address) {
|
||||
ipv6Ifaces.add(interf);
|
||||
}
|
||||
}
|
||||
if (ipv6Ifaces.isEmpty()) {
|
||||
system.log().info("JavaUdpMulticastTest skipped since no ipv6 interface supporting multicast could be found");
|
||||
} else {
|
||||
// lots of problems with choosing the wrong interface for this test depending
|
||||
// on the platform (awsdl0 can't be used on OSX, docker[0-9] can't be used in a docker machine etc.)
|
||||
// therefore: try hard to find an interface that _does_ work, and only fail if there was any potentially
|
||||
// working interfaces but all failed
|
||||
for (Iterator<NetworkInterface> interfaceIterator = ipv6Ifaces.iterator(); interfaceIterator.hasNext(); ) {
|
||||
NetworkInterface ipv6Iface = interfaceIterator.next();
|
||||
// host assigned link local multicast address http://tools.ietf.org/html/rfc3307#section-4.3.2
|
||||
// generate a random 32 bit multicast address with the high order bit set
|
||||
final String randomAddress = Long.toHexString(((long) Math.abs(new Random().nextInt())) | (1L << 31)).toUpperCase();
|
||||
final StringBuilder groupBuilder = new StringBuilder("FF02:");
|
||||
for (int i = 0; i < 2; i += 1) {
|
||||
groupBuilder.append(":");
|
||||
groupBuilder.append(randomAddress.subSequence(i * 4, i * 4 + 4));
|
||||
}
|
||||
final String group = groupBuilder.toString();
|
||||
final Integer port = SocketUtil.temporaryUdpIpv6Port(ipv6Iface);
|
||||
final String msg = "ohi";
|
||||
final ActorRef sink = getRef();
|
||||
final String iface = ipv6Iface.getName();
|
||||
|
||||
final ActorRef listener = system.actorOf(Props.create(JavaUdpMulticast.Listener.class, iface, group, port, sink));
|
||||
|
||||
try {
|
||||
expectMsgClass(Udp.Bound.class);
|
||||
final ActorRef sender = system.actorOf(Props.create(JavaUdpMulticast.Sender.class, iface, group, port, msg));
|
||||
expectMsgEquals(msg);
|
||||
// success with one interface is enough
|
||||
break;
|
||||
|
||||
} catch (AssertionError ex) {
|
||||
if (!interfaceIterator.hasNext()) throw ex;
|
||||
else {
|
||||
system.log().info("Failed to run test on interface {}", ipv6Iface.getDisplayName());
|
||||
}
|
||||
} finally {
|
||||
// unbind
|
||||
system.stop(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ipv6Ifaces.isEmpty()) {
|
||||
system
|
||||
.log()
|
||||
.info(
|
||||
"JavaUdpMulticastTest skipped since no ipv6 interface supporting multicast could be found");
|
||||
} else {
|
||||
// lots of problems with choosing the wrong interface for this test depending
|
||||
// on the platform (awsdl0 can't be used on OSX, docker[0-9] can't be used in a docker
|
||||
// machine etc.)
|
||||
// therefore: try hard to find an interface that _does_ work, and only fail if there was
|
||||
// any potentially
|
||||
// working interfaces but all failed
|
||||
for (Iterator<NetworkInterface> interfaceIterator = ipv6Ifaces.iterator();
|
||||
interfaceIterator.hasNext(); ) {
|
||||
NetworkInterface ipv6Iface = interfaceIterator.next();
|
||||
// host assigned link local multicast address
|
||||
// http://tools.ietf.org/html/rfc3307#section-4.3.2
|
||||
// generate a random 32 bit multicast address with the high order bit set
|
||||
final String randomAddress =
|
||||
Long.toHexString(((long) Math.abs(new Random().nextInt())) | (1L << 31))
|
||||
.toUpperCase();
|
||||
final StringBuilder groupBuilder = new StringBuilder("FF02:");
|
||||
for (int i = 0; i < 2; i += 1) {
|
||||
groupBuilder.append(":");
|
||||
groupBuilder.append(randomAddress.subSequence(i * 4, i * 4 + 4));
|
||||
}
|
||||
}};
|
||||
}
|
||||
final String group = groupBuilder.toString();
|
||||
final Integer port = SocketUtil.temporaryUdpIpv6Port(ipv6Iface);
|
||||
final String msg = "ohi";
|
||||
final ActorRef sink = getRef();
|
||||
final String iface = ipv6Iface.getName();
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() {
|
||||
TestKit.shutdownActorSystem(system);
|
||||
system = null;
|
||||
}
|
||||
final ActorRef listener =
|
||||
system.actorOf(
|
||||
Props.create(JavaUdpMulticast.Listener.class, iface, group, port, sink));
|
||||
|
||||
try {
|
||||
expectMsgClass(Udp.Bound.class);
|
||||
final ActorRef sender =
|
||||
system.actorOf(
|
||||
Props.create(JavaUdpMulticast.Sender.class, iface, group, port, msg));
|
||||
expectMsgEquals(msg);
|
||||
// success with one interface is enough
|
||||
break;
|
||||
|
||||
} catch (AssertionError ex) {
|
||||
if (!interfaceIterator.hasNext()) throw ex;
|
||||
else {
|
||||
system.log().info("Failed to run test on interface {}", ipv6Iface.getDisplayName());
|
||||
}
|
||||
} finally {
|
||||
// unbind
|
||||
system.stop(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() {
|
||||
TestKit.shutdownActorSystem(system);
|
||||
system = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import org.junit.Test;
|
|||
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.AbstractActor;
|
||||
//#imports
|
||||
// #imports
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -19,11 +19,11 @@ import akka.io.UdpConnected;
|
|||
import akka.io.UdpConnectedMessage;
|
||||
import akka.io.UdpSO;
|
||||
import akka.util.ByteString;
|
||||
//#imports
|
||||
// #imports
|
||||
|
||||
public class UdpConnectedDocTest {
|
||||
|
||||
static public class Demo extends AbstractActor {
|
||||
public static class Demo extends AbstractActor {
|
||||
ActorRef connectionActor = null;
|
||||
ActorRef handler = getSelf();
|
||||
ActorSystem system = getContext().getSystem();
|
||||
|
|
@ -31,55 +31,63 @@ public class UdpConnectedDocTest {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
ReceiveBuilder builder = receiveBuilder();
|
||||
builder.matchEquals("connect", message -> {
|
||||
//#manager
|
||||
final ActorRef udp = UdpConnected.get(system).manager();
|
||||
//#manager
|
||||
//#connect
|
||||
final InetSocketAddress remoteAddr =
|
||||
new InetSocketAddress("127.0.0.1", 12345);
|
||||
udp.tell(UdpConnectedMessage.connect(handler, remoteAddr), getSelf());
|
||||
//#connect
|
||||
//#connect-with-options
|
||||
final InetSocketAddress localAddr =
|
||||
new InetSocketAddress("127.0.0.1", 1234);
|
||||
final List<Inet.SocketOption> options =
|
||||
new ArrayList<Inet.SocketOption>();
|
||||
options.add(UdpSO.broadcast(true));
|
||||
udp.tell(UdpConnectedMessage.connect(handler, remoteAddr, localAddr, options), getSelf());
|
||||
//#connect-with-options
|
||||
});
|
||||
//#connected
|
||||
builder.match(UdpConnected.Connected.class, conn -> {
|
||||
connectionActor = getSender(); // Save the worker ref for later use
|
||||
});
|
||||
//#connected
|
||||
//#received
|
||||
builder.matchEquals(
|
||||
"connect",
|
||||
message -> {
|
||||
// #manager
|
||||
final ActorRef udp = UdpConnected.get(system).manager();
|
||||
// #manager
|
||||
// #connect
|
||||
final InetSocketAddress remoteAddr = new InetSocketAddress("127.0.0.1", 12345);
|
||||
udp.tell(UdpConnectedMessage.connect(handler, remoteAddr), getSelf());
|
||||
// #connect
|
||||
// #connect-with-options
|
||||
final InetSocketAddress localAddr = new InetSocketAddress("127.0.0.1", 1234);
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
options.add(UdpSO.broadcast(true));
|
||||
udp.tell(
|
||||
UdpConnectedMessage.connect(handler, remoteAddr, localAddr, options), getSelf());
|
||||
// #connect-with-options
|
||||
});
|
||||
// #connected
|
||||
builder.match(
|
||||
UdpConnected.Connected.class,
|
||||
conn -> {
|
||||
connectionActor = getSender(); // Save the worker ref for later use
|
||||
});
|
||||
// #connected
|
||||
// #received
|
||||
builder
|
||||
.match(UdpConnected.Received.class, recv -> {
|
||||
final ByteString data = recv.data();
|
||||
// and do something with the received data ...
|
||||
})
|
||||
.match(UdpConnected.CommandFailed.class, failed -> {
|
||||
final UdpConnected.Command command = failed.cmd();
|
||||
// react to failed connect, etc.
|
||||
})
|
||||
.match(UdpConnected.Disconnected.class, x -> {
|
||||
// do something on disconnect
|
||||
});
|
||||
//#received
|
||||
builder.matchEquals("send", x -> {
|
||||
ByteString data = ByteString.empty();
|
||||
//#send
|
||||
connectionActor.tell(UdpConnectedMessage.send(data), getSelf());
|
||||
//#send
|
||||
});
|
||||
.match(
|
||||
UdpConnected.Received.class,
|
||||
recv -> {
|
||||
final ByteString data = recv.data();
|
||||
// and do something with the received data ...
|
||||
})
|
||||
.match(
|
||||
UdpConnected.CommandFailed.class,
|
||||
failed -> {
|
||||
final UdpConnected.Command command = failed.cmd();
|
||||
// react to failed connect, etc.
|
||||
})
|
||||
.match(
|
||||
UdpConnected.Disconnected.class,
|
||||
x -> {
|
||||
// do something on disconnect
|
||||
});
|
||||
// #received
|
||||
builder.matchEquals(
|
||||
"send",
|
||||
x -> {
|
||||
ByteString data = ByteString.empty();
|
||||
// #send
|
||||
connectionActor.tell(UdpConnectedMessage.send(data), getSelf());
|
||||
// #send
|
||||
});
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void demonstrateConnect() {
|
||||
}
|
||||
|
||||
public void demonstrateConnect() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package jdocs.io;
|
||||
|
||||
//#imports
|
||||
// #imports
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.PoisonPill;
|
||||
import akka.actor.AbstractActor;
|
||||
|
|
@ -15,105 +15,116 @@ import akka.io.UdpMessage;
|
|||
import akka.util.ByteString;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
//#imports
|
||||
// #imports
|
||||
|
||||
public class UdpDocTest {
|
||||
|
||||
//#sender
|
||||
// #sender
|
||||
public static class SimpleSender extends AbstractActor {
|
||||
final InetSocketAddress remote;
|
||||
|
||||
public SimpleSender(InetSocketAddress remote) {
|
||||
this.remote = remote;
|
||||
|
||||
|
||||
// request creation of a SimpleSender
|
||||
final ActorRef mgr = Udp.get(getContext().getSystem()).getManager();
|
||||
mgr.tell(UdpMessage.simpleSender(), getSelf());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Udp.SimpleSenderReady.class, message -> {
|
||||
getContext().become(ready(getSender()));
|
||||
//#sender
|
||||
getSender().tell(UdpMessage.send(ByteString.fromString("hello"), remote), getSelf());
|
||||
//#sender
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
Udp.SimpleSenderReady.class,
|
||||
message -> {
|
||||
getContext().become(ready(getSender()));
|
||||
// #sender
|
||||
getSender()
|
||||
.tell(UdpMessage.send(ByteString.fromString("hello"), remote), getSelf());
|
||||
// #sender
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private Receive ready(final ActorRef send) {
|
||||
return receiveBuilder()
|
||||
.match(String.class, message -> {
|
||||
send.tell(UdpMessage.send(ByteString.fromString(message), remote), getSelf());
|
||||
//#sender
|
||||
if (message.equals("world")) {
|
||||
send.tell(PoisonPill.getInstance(), getSelf());
|
||||
}
|
||||
//#sender
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
String.class,
|
||||
message -> {
|
||||
send.tell(UdpMessage.send(ByteString.fromString(message), remote), getSelf());
|
||||
// #sender
|
||||
if (message.equals("world")) {
|
||||
send.tell(PoisonPill.getInstance(), getSelf());
|
||||
}
|
||||
// #sender
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#sender
|
||||
|
||||
//#listener
|
||||
// #sender
|
||||
|
||||
// #listener
|
||||
public static class Listener extends AbstractActor {
|
||||
final ActorRef nextActor;
|
||||
|
||||
public Listener(ActorRef nextActor) {
|
||||
this.nextActor = nextActor;
|
||||
|
||||
|
||||
// request creation of a bound listen socket
|
||||
final ActorRef mgr = Udp.get(getContext().getSystem()).getManager();
|
||||
mgr.tell(
|
||||
UdpMessage.bind(getSelf(), new InetSocketAddress("localhost", 0)),
|
||||
getSelf());
|
||||
mgr.tell(UdpMessage.bind(getSelf(), new InetSocketAddress("localhost", 0)), getSelf());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Udp.Bound.class, bound -> {
|
||||
//#listener
|
||||
nextActor.tell(bound.localAddress(), getSender());
|
||||
//#listener
|
||||
getContext().become(ready(getSender()));
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
Udp.Bound.class,
|
||||
bound -> {
|
||||
// #listener
|
||||
nextActor.tell(bound.localAddress(), getSender());
|
||||
// #listener
|
||||
getContext().become(ready(getSender()));
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private Receive ready(final ActorRef socket) {
|
||||
return receiveBuilder()
|
||||
.match(Udp.Received.class, r -> {
|
||||
// echo server example: send back the data
|
||||
socket.tell(UdpMessage.send(r.data(), r.sender()), getSelf());
|
||||
// or do some processing and forward it on
|
||||
final Object processed = // parse data etc., e.g. using PipelineStage
|
||||
// #listener
|
||||
r.data().utf8String();
|
||||
//#listener
|
||||
nextActor.tell(processed, getSelf());
|
||||
})
|
||||
.matchEquals(UdpMessage.unbind(), message -> {
|
||||
socket.tell(message, getSelf());
|
||||
})
|
||||
.match(Udp.Unbound.class, message -> {
|
||||
getContext().stop(getSelf());
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
Udp.Received.class,
|
||||
r -> {
|
||||
// echo server example: send back the data
|
||||
socket.tell(UdpMessage.send(r.data(), r.sender()), getSelf());
|
||||
// or do some processing and forward it on
|
||||
final Object processed = // parse data etc., e.g. using PipelineStage
|
||||
// #listener
|
||||
r.data().utf8String();
|
||||
// #listener
|
||||
nextActor.tell(processed, getSelf());
|
||||
})
|
||||
.matchEquals(
|
||||
UdpMessage.unbind(),
|
||||
message -> {
|
||||
socket.tell(message, getSelf());
|
||||
})
|
||||
.match(
|
||||
Udp.Unbound.class,
|
||||
message -> {
|
||||
getContext().stop(getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#listener
|
||||
|
||||
//#connected
|
||||
public static class Connected extends AbstractActor {
|
||||
// #listener
|
||||
|
||||
// #connected
|
||||
public static class Connected extends AbstractActor {
|
||||
final InetSocketAddress remote;
|
||||
|
||||
public Connected(InetSocketAddress remote) {
|
||||
this.remote = remote;
|
||||
|
||||
|
||||
// create a restricted a.k.a. “connected” socket
|
||||
final ActorRef mgr = UdpConnected.get(getContext().getSystem()).getManager();
|
||||
mgr.tell(UdpConnectedMessage.connect(getSelf(), remote), getSelf());
|
||||
|
|
@ -122,43 +133,49 @@ public class UdpDocTest {
|
|||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(UdpConnected.Connected.class, message -> {
|
||||
getContext().become(ready(getSender()));
|
||||
//#connected
|
||||
getSender()
|
||||
.tell(UdpConnectedMessage.send(ByteString.fromString("hello")),
|
||||
getSelf());
|
||||
//#connected
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
UdpConnected.Connected.class,
|
||||
message -> {
|
||||
getContext().become(ready(getSender()));
|
||||
// #connected
|
||||
getSender()
|
||||
.tell(UdpConnectedMessage.send(ByteString.fromString("hello")), getSelf());
|
||||
// #connected
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private Receive ready(final ActorRef connection) {
|
||||
return receiveBuilder()
|
||||
.match(UdpConnected.Received.class, r -> {
|
||||
// process data, send it on, etc.
|
||||
// #connected
|
||||
if (r.data().utf8String().equals("hello")) {
|
||||
connection.tell(
|
||||
UdpConnectedMessage.send(ByteString.fromString("world")),
|
||||
getSelf());
|
||||
}
|
||||
// #connected
|
||||
})
|
||||
.match(String.class, str -> {
|
||||
connection
|
||||
.tell(UdpConnectedMessage.send(ByteString.fromString(str)),
|
||||
getSelf());
|
||||
})
|
||||
.matchEquals(UdpConnectedMessage.disconnect(), message -> {
|
||||
connection.tell(message, getSelf());
|
||||
})
|
||||
.match(UdpConnected.Disconnected.class, x -> {
|
||||
getContext().stop(getSelf());
|
||||
})
|
||||
.build();
|
||||
.match(
|
||||
UdpConnected.Received.class,
|
||||
r -> {
|
||||
// process data, send it on, etc.
|
||||
// #connected
|
||||
if (r.data().utf8String().equals("hello")) {
|
||||
connection.tell(
|
||||
UdpConnectedMessage.send(ByteString.fromString("world")), getSelf());
|
||||
}
|
||||
// #connected
|
||||
})
|
||||
.match(
|
||||
String.class,
|
||||
str -> {
|
||||
connection.tell(UdpConnectedMessage.send(ByteString.fromString(str)), getSelf());
|
||||
})
|
||||
.matchEquals(
|
||||
UdpConnectedMessage.disconnect(),
|
||||
message -> {
|
||||
connection.tell(message, getSelf());
|
||||
})
|
||||
.match(
|
||||
UdpConnected.Disconnected.class,
|
||||
x -> {
|
||||
getContext().stop(getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#connected
|
||||
// #connected
|
||||
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue