/* * Copyright (C) 2015 SoftIndex LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.datakernel.rpc.client.sender; import com.google.common.net.InetAddresses; import io.datakernel.async.ResultCallback; import io.datakernel.async.ResultCallbackFuture; import io.datakernel.bytebuf.ByteBufPool; import io.datakernel.eventloop.Eventloop; import io.datakernel.rpc.client.RpcClient; import io.datakernel.rpc.hash.ShardingFunction; import io.datakernel.rpc.server.RpcRequestHandler; import io.datakernel.rpc.server.RpcServer; import io.datakernel.serializer.annotations.Deserialize; import io.datakernel.serializer.annotations.Serialize; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.net.InetSocketAddress; import java.util.concurrent.ExecutionException; import static io.datakernel.bytebuf.ByteBufPool.getPoolItemsString; import static io.datakernel.eventloop.EventloopThreadFactory.defaultEventloopThreadFactory; import static io.datakernel.eventloop.FatalErrorHandlers.rethrowOnAnyError; import static io.datakernel.rpc.client.sender.RpcStrategies.*; import static org.junit.Assert.assertEquals; public class RpcBlockingTest { private static final int PORT_1 = 10001; private static final int PORT_2 = 10002; private static final int PORT_3 = 10003; private static final int TIMEOUT = 1500; private Eventloop eventloop; private Thread thread; private RpcServer serverOne; private RpcServer serverTwo; private RpcServer serverThree; @Before public void setUp() throws Exception { ByteBufPool.clear(); ByteBufPool.setSizes(0, Integer.MAX_VALUE); eventloop = Eventloop.create().withFatalErrorHandler(rethrowOnAnyError()); serverOne = RpcServer.create(eventloop) .withMessageTypes(HelloRequest.class, HelloResponse.class) .withHandler(HelloRequest.class, HelloResponse.class, helloServiceRequestHandler(new HelloServiceImplOne())) .withListenPort(PORT_1); serverOne.listen(); serverTwo = RpcServer.create(eventloop) .withMessageTypes(HelloRequest.class, HelloResponse.class) .withHandler(HelloRequest.class, HelloResponse.class, helloServiceRequestHandler(new HelloServiceImplTwo())) .withListenPort(PORT_2); serverTwo.listen(); serverThree = RpcServer.create(eventloop) .withMessageTypes(HelloRequest.class, HelloResponse.class) .withHandler(HelloRequest.class, HelloResponse.class, helloServiceRequestHandler(new HelloServiceImplThree())) .withListenPort(PORT_3); serverThree.listen(); thread = defaultEventloopThreadFactory().newThread(eventloop); thread.start(); } @After public void tearDown() throws InterruptedException { thread.join(); } @Test public void testBlockingCall() throws Exception { InetSocketAddress address1 = new InetSocketAddress(InetAddresses.forString("127.0.0.1"), PORT_1); InetSocketAddress address2 = new InetSocketAddress(InetAddresses.forString("127.0.0.1"), PORT_2); InetSocketAddress address3 = new InetSocketAddress(InetAddresses.forString("127.0.0.1"), PORT_3); ShardingFunction<HelloRequest> shardingFunction = new ShardingFunction<HelloRequest>() { @Override public int getShard(HelloRequest item) { int shard = 0; if (item.name.startsWith("S")) { shard = 1; } return shard; } }; RpcClient client = RpcClient.create(eventloop) .withMessageTypes(HelloRequest.class, HelloResponse.class) .withStrategy( roundRobin( server(address1), sharding(shardingFunction, server(address2), server(address3)).withMinActiveSubStrategies(2))); client.startFuture().get(); String currentName = "John"; String currentResponse = blockingRequest(client, currentName); System.out.println("Request with name \"" + currentName + "\": " + currentResponse); assertEquals("Hello, " + currentName + "!", currentResponse); currentName = "Winston"; currentResponse = blockingRequest(client, currentName); System.out.println("Request with name \"" + currentName + "\": " + currentResponse); assertEquals("Hello Hello, " + currentName + "!", currentResponse); currentName = "Ann"; currentResponse = blockingRequest(client, currentName); System.out.println("Request with name \"" + currentName + "\": " + currentResponse); assertEquals("Hello, " + currentName + "!", currentResponse); currentName = "Emma"; currentResponse = blockingRequest(client, currentName); System.out.println("Request with name \"" + currentName + "\": " + currentResponse); assertEquals("Hello Hello, " + currentName + "!", currentResponse); currentName = "Lukas"; currentResponse = blockingRequest(client, currentName); System.out.println("Request with name \"" + currentName + "\": " + currentResponse); assertEquals("Hello, " + currentName + "!", currentResponse); currentName = "Sophia"; // name starts with "s", so hash code is different from previous examples currentResponse = blockingRequest(client, currentName); System.out.println("Request with name \"" + currentName + "\": " + currentResponse); assertEquals("Hello Hello Hello, " + currentName + "!", currentResponse); client.stopFuture().get(); serverOne.closeFuture().get(); serverTwo.closeFuture().get(); serverThree.closeFuture().get(); assertEquals(getPoolItemsString(), ByteBufPool.getCreatedItems(), ByteBufPool.getPoolItems()); } private static String blockingRequest(final RpcClient rpcClient, final String name) throws Exception { try { final ResultCallbackFuture<HelloResponse> future = ResultCallbackFuture.create(); rpcClient.getEventloop().execute(new Runnable() { @Override public void run() { rpcClient.sendRequest(new HelloRequest(name), TIMEOUT, future); } }); return future.get().message; } catch (ExecutionException e) { throw (Exception) e.getCause(); } } private interface HelloService { String hello(String name) throws Exception; } private static class HelloServiceImplOne implements HelloService { @Override public String hello(String name) throws Exception { if (name.equals("--")) { throw new Exception("Illegal name"); } return "Hello, " + name + "!"; } } private static class HelloServiceImplTwo implements HelloService { @Override public String hello(String name) throws Exception { if (name.equals("--")) { throw new Exception("Illegal name"); } return "Hello Hello, " + name + "!"; } } private static class HelloServiceImplThree implements HelloService { @Override public String hello(String name) throws Exception { if (name.equals("--")) { throw new Exception("Illegal name"); } return "Hello Hello Hello, " + name + "!"; } } protected static class HelloRequest { @Serialize(order = 0) public String name; public HelloRequest(@Deserialize("name") String name) { this.name = name; } } protected static class HelloResponse { @Serialize(order = 0) public String message; public HelloResponse(@Deserialize("message") String message) { this.message = message; } } private static RpcRequestHandler<HelloRequest, HelloResponse> helloServiceRequestHandler(final HelloService helloService) { return new RpcRequestHandler<HelloRequest, HelloResponse>() { @Override public void run(HelloRequest request, ResultCallback<HelloResponse> callback) { String result; try { result = helloService.hello(request.name); } catch (Exception e) { callback.setException(e); return; } callback.setResult(new HelloResponse(result)); } }; } }