Formatting java codes with sbt-java-formatter.

This commit is contained in:
hepin1989 2019-01-12 04:00:53 +08:00
parent 27500001ea
commit 998c5a9285
401 changed files with 19750 additions and 17450 deletions

View file

@ -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

View file

@ -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

View file

@ -25,7 +25,7 @@ public class BlockingDispatcherTest {
Thread.sleep(5000 * 6);
} catch (InterruptedException e) {
//swallow the exception
// swallow the exception
} finally {
system.terminate();
}

View file

@ -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

View file

@ -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
}
}

View file

@ -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 {
}
};
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
}
}

View file

@ -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");
}
};
}
}

View file

@ -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;
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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();
}
};
}
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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();
}

View file

@ -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
}

View file

@ -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
}
}
}

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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/"));
}
};
}
}

View file

@ -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
}
}
}

View file

@ -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));
}
}

View file

@ -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) {}
}
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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;
}
}

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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;
}
}

View file

@ -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

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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

View file

@ -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

View file

@ -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();
}
}

View file

@ -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");
}
}

View file

@ -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
}
}
}

View file

@ -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
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
}
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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();
}
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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));
}
}

View file

@ -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

View file

@ -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

View file

@ -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();
}
}

View file

@ -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 events 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 events 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 events 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
}
}

View file

@ -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
}

View file

@ -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
}
}
}

View file

@ -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
}
}
}

View file

@ -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

View file

@ -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();
}
}

View file

@ -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
}
}

View file

@ -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();
}
}
}

View file

@ -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;
}
}

View file

@ -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() {}
}

View file

@ -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