2016-01-13 16:25:24 +01:00
|
|
|
/**
|
2016-01-25 10:16:14 +01:00
|
|
|
* Copyright (C) 2015-2016 Typesafe Inc. <http://www.typesafe.com>
|
2016-01-13 16:25:24 +01:00
|
|
|
*/
|
|
|
|
|
package docs.stream.io;
|
|
|
|
|
|
2016-01-21 16:37:26 +01:00
|
|
|
import java.util.concurrent.CompletionStage;
|
2016-01-13 16:25:24 +01:00
|
|
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
|
|
|
|
2016-01-20 10:00:37 +02:00
|
|
|
import akka.NotUsed;
|
2016-02-16 17:47:27 +01:00
|
|
|
import akka.stream.javadsl.Framing;
|
2016-02-11 16:39:25 +01:00
|
|
|
import docs.AbstractJavaTest;
|
2016-01-13 16:25:24 +01:00
|
|
|
import docs.stream.SilenceSystemOut;
|
|
|
|
|
import java.net.InetSocketAddress;
|
|
|
|
|
|
|
|
|
|
import docs.util.SocketUtils;
|
|
|
|
|
import org.junit.AfterClass;
|
|
|
|
|
import org.junit.BeforeClass;
|
|
|
|
|
import org.junit.Test;
|
|
|
|
|
import scala.concurrent.Future;
|
|
|
|
|
|
|
|
|
|
import akka.actor.ActorSystem;
|
|
|
|
|
import akka.stream.*;
|
|
|
|
|
import akka.stream.javadsl.*;
|
|
|
|
|
import akka.stream.javadsl.Tcp.*;
|
|
|
|
|
import akka.stream.stage.*;
|
|
|
|
|
import akka.testkit.JavaTestKit;
|
|
|
|
|
import akka.testkit.TestProbe;
|
|
|
|
|
import akka.util.ByteString;
|
|
|
|
|
|
2016-02-11 16:39:25 +01:00
|
|
|
public class StreamTcpDocTest extends AbstractJavaTest {
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
static ActorSystem system;
|
2016-02-11 16:39:25 +01:00
|
|
|
static Materializer mat;
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
@BeforeClass
|
|
|
|
|
public static void setup() {
|
|
|
|
|
system = ActorSystem.create("StreamTcpDocTest");
|
2016-02-11 16:39:25 +01:00
|
|
|
mat = ActorMaterializer.create(system);
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@AfterClass
|
|
|
|
|
public static void tearDown() {
|
|
|
|
|
JavaTestKit.shutdownActorSystem(system);
|
|
|
|
|
system = null;
|
2016-02-11 16:39:25 +01:00
|
|
|
mat = null;
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final SilenceSystemOut.System System = SilenceSystemOut.get();
|
|
|
|
|
|
|
|
|
|
private final ConcurrentLinkedQueue<String> input = new ConcurrentLinkedQueue<String>();
|
|
|
|
|
{
|
|
|
|
|
input.add("Hello world");
|
|
|
|
|
input.add("What a lovely day");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String readLine(String prompt) {
|
|
|
|
|
String s = input.poll();
|
|
|
|
|
return (s == null ? "q": s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void demonstrateSimpleServerConnection() {
|
|
|
|
|
{
|
|
|
|
|
//#echo-server-simple-bind
|
|
|
|
|
// IncomingConnection and ServerBinding imported from Tcp
|
2016-01-21 16:37:26 +01:00
|
|
|
final Source<IncomingConnection, CompletionStage<ServerBinding>> connections =
|
2016-01-13 16:25:24 +01:00
|
|
|
Tcp.get(system).bind("127.0.0.1", 8889);
|
|
|
|
|
//#echo-server-simple-bind
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
final InetSocketAddress localhost = SocketUtils.temporaryServerAddress();
|
2016-01-21 16:37:26 +01:00
|
|
|
final Source<IncomingConnection, CompletionStage<ServerBinding>> connections =
|
2016-01-13 16:25:24 +01:00
|
|
|
Tcp.get(system).bind(localhost.getHostName(), localhost.getPort()); // TODO getHostString in Java7
|
|
|
|
|
|
|
|
|
|
//#echo-server-simple-handle
|
|
|
|
|
connections.runForeach(connection -> {
|
|
|
|
|
System.out.println("New connection from: " + connection.remoteAddress());
|
|
|
|
|
|
2016-01-20 10:00:37 +02:00
|
|
|
final Flow<ByteString, ByteString, NotUsed> echo = Flow.of(ByteString.class)
|
2016-01-13 16:25:24 +01:00
|
|
|
.via(Framing.delimiter(ByteString.fromString("\n"), 256, false))
|
2016-02-11 16:39:25 +01:00
|
|
|
.map(ByteString::utf8String)
|
2016-01-13 16:25:24 +01:00
|
|
|
.map(s -> s + "!!!\n")
|
2016-02-11 16:39:25 +01:00
|
|
|
.map(ByteString::fromString);
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
connection.handleWith(echo, mat);
|
|
|
|
|
}, mat);
|
|
|
|
|
//#echo-server-simple-handle
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void actuallyWorkingClientServerApp() {
|
|
|
|
|
|
|
|
|
|
final InetSocketAddress localhost = SocketUtils.temporaryServerAddress();
|
|
|
|
|
|
|
|
|
|
final TestProbe serverProbe = new TestProbe(system);
|
|
|
|
|
|
2016-01-21 16:37:26 +01:00
|
|
|
final Source<IncomingConnection,CompletionStage<ServerBinding>> connections =
|
2016-02-11 16:39:25 +01:00
|
|
|
Tcp.get(system).bind(localhost.getHostString(), localhost.getPort());
|
2016-01-13 16:25:24 +01:00
|
|
|
//#welcome-banner-chat-server
|
|
|
|
|
connections.runForeach(connection -> {
|
|
|
|
|
// server logic, parses incoming commands
|
2016-02-11 16:39:25 +01:00
|
|
|
final Flow<String, String, NotUsed> commandParser =
|
|
|
|
|
Flow.<String>create()
|
|
|
|
|
.takeWhile(elem -> !elem.equals("BYE"))
|
|
|
|
|
.map(elem -> elem + "!");
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
final String welcomeMsg = "Welcome to: " + connection.localAddress() +
|
2016-02-11 16:39:25 +01:00
|
|
|
" you are: " + connection.remoteAddress() + "!";
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2016-02-11 16:39:25 +01:00
|
|
|
final Source<String, NotUsed> welcome = Source.single(welcomeMsg);
|
|
|
|
|
final Flow<ByteString, ByteString, NotUsed> serverLogic =
|
2016-01-13 16:25:24 +01:00
|
|
|
Flow.of(ByteString.class)
|
|
|
|
|
.via(Framing.delimiter(ByteString.fromString("\n"), 256, false))
|
2016-02-11 16:39:25 +01:00
|
|
|
.map(ByteString::utf8String)
|
2016-01-13 16:25:24 +01:00
|
|
|
//#welcome-banner-chat-server
|
|
|
|
|
.map(command -> {
|
|
|
|
|
serverProbe.ref().tell(command, null);
|
|
|
|
|
return command;
|
|
|
|
|
})
|
|
|
|
|
//#welcome-banner-chat-server
|
2016-02-11 16:39:25 +01:00
|
|
|
.via(commandParser)
|
|
|
|
|
.merge(welcome)
|
2016-01-13 16:25:24 +01:00
|
|
|
.map(s -> s + "\n")
|
2016-02-11 16:39:25 +01:00
|
|
|
.map(ByteString::fromString);
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
connection.handleWith(serverLogic, mat);
|
|
|
|
|
}, mat);
|
|
|
|
|
|
|
|
|
|
//#welcome-banner-chat-server
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
//#repl-client
|
2016-01-21 16:37:26 +01:00
|
|
|
final Flow<ByteString, ByteString, CompletionStage<OutgoingConnection>> connection =
|
2016-01-13 16:25:24 +01:00
|
|
|
Tcp.get(system).outgoingConnection("127.0.0.1", 8889);
|
|
|
|
|
//#repl-client
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2016-01-21 16:37:26 +01:00
|
|
|
final Flow<ByteString, ByteString, CompletionStage<OutgoingConnection>> connection =
|
|
|
|
|
Tcp.get(system).outgoingConnection(localhost.getHostString(), localhost.getPort());
|
2016-01-13 16:25:24 +01:00
|
|
|
//#repl-client
|
2016-02-11 16:39:25 +01:00
|
|
|
final Flow<String, ByteString, NotUsed> replParser =
|
|
|
|
|
Flow.<String>create()
|
|
|
|
|
.takeWhile(elem -> !elem.equals("q"))
|
|
|
|
|
.concat(Source.single("BYE")) // will run after the original flow completes
|
|
|
|
|
.map(elem -> ByteString.fromString(elem + "\n"));
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2016-01-20 10:00:37 +02:00
|
|
|
final Flow<ByteString, ByteString, NotUsed> repl = Flow.of(ByteString.class)
|
2016-01-13 16:25:24 +01:00
|
|
|
.via(Framing.delimiter(ByteString.fromString("\n"), 256, false))
|
2016-02-11 16:39:25 +01:00
|
|
|
.map(ByteString::utf8String)
|
2016-01-13 16:25:24 +01:00
|
|
|
.map(text -> {System.out.println("Server: " + text); return "next";})
|
|
|
|
|
.map(elem -> readLine("> "))
|
2016-02-11 16:39:25 +01:00
|
|
|
.via(replParser);
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
connection.join(repl).run(mat);
|
2016-02-11 16:39:25 +01:00
|
|
|
//#repl-client
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
|
2016-02-11 16:39:25 +01:00
|
|
|
|
|
|
|
|
|
2016-01-13 16:25:24 +01:00
|
|
|
serverProbe.expectMsg("Hello world");
|
|
|
|
|
serverProbe.expectMsg("What a lovely day");
|
|
|
|
|
serverProbe.expectMsg("BYE");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|