implement and document Pipelines, see #3174
- heavily inspired by spray.io.Pipeline - fully functional style: a stage returns the resulting commands and events, which makes it impossible to mess with the pipeline from the inside - object allocations are optimized away for emtpy and 1-elem results - added type-safety, verifying that stages match up - management commands “from the side” for configuration or async events - full Java API and docs
This commit is contained in:
parent
d9d7d45ac2
commit
d794b14b2b
18 changed files with 2530 additions and 64 deletions
167
akka-docs/rst/java/code/docs/io/japi/PipelineTest.java
Normal file
167
akka-docs/rst/java/code/docs/io/japi/PipelineTest.java
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/**
|
||||
* Copyright (C) 2013 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.io.japi;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import scala.concurrent.duration.Duration;
|
||||
|
||||
import akka.actor.Actor;
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.PoisonPill;
|
||||
import akka.actor.Props;
|
||||
import akka.actor.UntypedActorFactory;
|
||||
import akka.io.AbstractPipelineContext;
|
||||
import akka.io.PipelineFactory;
|
||||
import akka.io.PipelineInjector;
|
||||
import akka.io.PipelineSink;
|
||||
import akka.io.PipelineStage;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import akka.testkit.TestProbe;
|
||||
import akka.util.ByteString;
|
||||
|
||||
public class PipelineTest {
|
||||
|
||||
//#message
|
||||
final Message msg = new Message(
|
||||
new Message.Person[] {
|
||||
new Message.Person("Alice", "Gibbons"),
|
||||
new Message.Person("Bob", "Sparseley")
|
||||
},
|
||||
new double[] { 1.0, 3.0, 5.0 });
|
||||
//#message
|
||||
|
||||
//#byteorder
|
||||
class Context extends AbstractPipelineContext implements HasByteOrder {
|
||||
|
||||
@Override
|
||||
public ByteOrder byteOrder() {
|
||||
return java.nio.ByteOrder.BIG_ENDIAN;
|
||||
}
|
||||
|
||||
}
|
||||
final Context ctx = new Context();
|
||||
//#byteorder
|
||||
|
||||
static ActorSystem system = null;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
system = ActorSystem.create("PipelineTest");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void teardown() {
|
||||
system.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void demonstratePipeline() throws Exception {
|
||||
final TestProbe probe = TestProbe.apply(system);
|
||||
final ActorRef commandHandler = probe.ref();
|
||||
final ActorRef eventHandler = probe.ref();
|
||||
//#build-sink
|
||||
final PipelineStage<Context, Message, ByteString, Message, ByteString> stages =
|
||||
PipelineStage.sequence(
|
||||
new MessageStage(),
|
||||
new LengthFieldFrame(10000)
|
||||
);
|
||||
|
||||
final PipelineSink<ByteString, Message> sink =
|
||||
new PipelineSink<ByteString, Message>() {
|
||||
|
||||
@Override
|
||||
public void onCommand(ByteString cmd) throws Throwable {
|
||||
commandHandler.tell(cmd, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(Message evt) throws Throwable {
|
||||
eventHandler.tell(evt, null);
|
||||
}
|
||||
};
|
||||
|
||||
final PipelineInjector<Message, ByteString> injector =
|
||||
PipelineFactory.buildWithSink(ctx, stages, sink);
|
||||
|
||||
injector.injectCommand(msg);
|
||||
//#build-sink
|
||||
final ByteString encoded = probe.expectMsgClass(ByteString.class);
|
||||
injector.injectEvent(encoded);
|
||||
final Message decoded = probe.expectMsgClass(Message.class);
|
||||
assert msg == decoded;
|
||||
}
|
||||
|
||||
static class SetTarget {
|
||||
final ActorRef ref;
|
||||
|
||||
public SetTarget(ActorRef ref) {
|
||||
super();
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
public ActorRef getRef() {
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTick() {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
final ActorRef proc = system.actorOf(new Props(
|
||||
new UntypedActorFactory() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Actor create() throws Exception {
|
||||
return new Processor(getRef(), getRef()) {
|
||||
|
||||
@Override
|
||||
public void onReceive(Object obj) throws Exception {
|
||||
if (obj.equals("fail!")) {
|
||||
throw new RuntimeException("FAIL!");
|
||||
}
|
||||
super.onReceive(obj);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}), "processor");
|
||||
expectMsgClass(TickGenerator.Tick.class);
|
||||
proc.tell(msg, null);
|
||||
final ByteString encoded = expectMsgClass(ByteString.class);
|
||||
proc.tell(encoded, null);
|
||||
final Message decoded = expectMsgClass(Message.class);
|
||||
assert msg == decoded;
|
||||
|
||||
new Within(Duration.create(1500, TimeUnit.MILLISECONDS),
|
||||
Duration.create(3, TimeUnit.SECONDS)) {
|
||||
protected void run() {
|
||||
expectMsgClass(TickGenerator.Tick.class);
|
||||
expectMsgClass(TickGenerator.Tick.class);
|
||||
}
|
||||
};
|
||||
proc.tell("fail!", null);
|
||||
new Within(Duration.create(1700, TimeUnit.MILLISECONDS),
|
||||
Duration.create(3, TimeUnit.SECONDS)) {
|
||||
protected void run() {
|
||||
expectMsgClass(TickGenerator.Tick.class);
|
||||
expectMsgClass(TickGenerator.Tick.class);
|
||||
proc.tell(PoisonPill.getInstance(), null);
|
||||
expectNoMsg();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue