ONOS-1983: Migrating all copycat Raft protocol specific communication to use ONO…
…S cluster communication primitives Change-Id: I3f07266e50106b1adc13f722c647686c2b42ef7f
Showing
10 changed files
with
259 additions
and
19 deletions
| ... | @@ -164,7 +164,7 @@ public interface ClusterCommunicationService { | ... | @@ -164,7 +164,7 @@ public interface ClusterCommunicationService { |
| 164 | * | 164 | * |
| 165 | * @param subject message subject | 165 | * @param subject message subject |
| 166 | * @param decoder decoder for resurrecting incoming message | 166 | * @param decoder decoder for resurrecting incoming message |
| 167 | - * @param handler handler function that process the incoming message and produces a reply | 167 | + * @param handler handler function that processes the incoming message and produces a reply |
| 168 | * @param encoder encoder for serializing reply | 168 | * @param encoder encoder for serializing reply |
| 169 | * @param executor executor to run this handler on | 169 | * @param executor executor to run this handler on |
| 170 | * @param <M> incoming message type | 170 | * @param <M> incoming message type |
| ... | @@ -180,6 +180,21 @@ public interface ClusterCommunicationService { | ... | @@ -180,6 +180,21 @@ public interface ClusterCommunicationService { |
| 180 | * Adds a new subscriber for the specified message subject. | 180 | * Adds a new subscriber for the specified message subject. |
| 181 | * | 181 | * |
| 182 | * @param subject message subject | 182 | * @param subject message subject |
| 183 | + * @param decoder decoder for resurrecting incoming message | ||
| 184 | + * @param handler handler function that processes the incoming message and produces a reply | ||
| 185 | + * @param encoder encoder for serializing reply | ||
| 186 | + * @param <M> incoming message type | ||
| 187 | + * @param <R> reply message type | ||
| 188 | + */ | ||
| 189 | + <M, R> void addSubscriber(MessageSubject subject, | ||
| 190 | + Function<byte[], M> decoder, | ||
| 191 | + Function<M, CompletableFuture<R>> handler, | ||
| 192 | + Function<R, byte[]> encoder); | ||
| 193 | + | ||
| 194 | + /** | ||
| 195 | + * Adds a new subscriber for the specified message subject. | ||
| 196 | + * | ||
| 197 | + * @param subject message subject | ||
| 183 | * @param decoder decoder to resurrecting incoming message | 198 | * @param decoder decoder to resurrecting incoming message |
| 184 | * @param handler handler for handling message | 199 | * @param handler handler for handling message |
| 185 | * @param executor executor to run this handler on | 200 | * @param executor executor to run this handler on | ... | ... |
| ... | @@ -62,6 +62,13 @@ public interface MessagingService { | ... | @@ -62,6 +62,13 @@ public interface MessagingService { |
| 62 | void registerHandler(String type, Function<byte[], byte[]> handler, Executor executor); | 62 | void registerHandler(String type, Function<byte[], byte[]> handler, Executor executor); |
| 63 | 63 | ||
| 64 | /** | 64 | /** |
| 65 | + * Registers a new message handler for message type. | ||
| 66 | + * @param type message type. | ||
| 67 | + * @param handler message handler | ||
| 68 | + */ | ||
| 69 | + void registerHandler(String type, Function<byte[], CompletableFuture<byte[]>> handler); | ||
| 70 | + | ||
| 71 | + /** | ||
| 65 | * Unregister current handler, if one exists for message type. | 72 | * Unregister current handler, if one exists for message type. |
| 66 | * @param type message type | 73 | * @param type message type |
| 67 | */ | 74 | */ | ... | ... |
| ... | @@ -21,6 +21,7 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -21,6 +21,7 @@ import org.apache.felix.scr.annotations.Deactivate; |
| 21 | import org.apache.felix.scr.annotations.Reference; | 21 | import org.apache.felix.scr.annotations.Reference; |
| 22 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 22 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 23 | import org.apache.felix.scr.annotations.Service; | 23 | import org.apache.felix.scr.annotations.Service; |
| 24 | +import org.onlab.util.Tools; | ||
| 24 | import org.onosproject.cluster.ClusterService; | 25 | import org.onosproject.cluster.ClusterService; |
| 25 | import org.onosproject.cluster.ControllerNode; | 26 | import org.onosproject.cluster.ControllerNode; |
| 26 | import org.onosproject.cluster.NodeId; | 27 | import org.onosproject.cluster.NodeId; |
| ... | @@ -182,11 +183,15 @@ public class ClusterCommunicationManager | ... | @@ -182,11 +183,15 @@ public class ClusterCommunicationManager |
| 182 | Function<M, byte[]> encoder, | 183 | Function<M, byte[]> encoder, |
| 183 | Function<byte[], R> decoder, | 184 | Function<byte[], R> decoder, |
| 184 | NodeId toNodeId) { | 185 | NodeId toNodeId) { |
| 185 | - ClusterMessage envelope = new ClusterMessage( | 186 | + try { |
| 186 | - clusterService.getLocalNode().id(), | 187 | + ClusterMessage envelope = new ClusterMessage( |
| 187 | - subject, | 188 | + clusterService.getLocalNode().id(), |
| 188 | - encoder.apply(message)); | 189 | + subject, |
| 189 | - return sendAndReceive(subject, envelope.getBytes(), toNodeId).thenApply(decoder); | 190 | + encoder.apply(message)); |
| 191 | + return sendAndReceive(subject, envelope.getBytes(), toNodeId).thenApply(decoder); | ||
| 192 | + } catch (Exception e) { | ||
| 193 | + return Tools.exceptionalFuture(e); | ||
| 194 | + } | ||
| 190 | } | 195 | } |
| 191 | 196 | ||
| 192 | private boolean unicastUnchecked(MessageSubject subject, byte[] payload, NodeId toNodeId) { | 197 | private boolean unicastUnchecked(MessageSubject subject, byte[] payload, NodeId toNodeId) { |
| ... | @@ -223,7 +228,6 @@ public class ClusterCommunicationManager | ... | @@ -223,7 +228,6 @@ public class ClusterCommunicationManager |
| 223 | messagingService.unregisterHandler(subject.value()); | 228 | messagingService.unregisterHandler(subject.value()); |
| 224 | } | 229 | } |
| 225 | 230 | ||
| 226 | - | ||
| 227 | @Override | 231 | @Override |
| 228 | public <M, R> void addSubscriber(MessageSubject subject, | 232 | public <M, R> void addSubscriber(MessageSubject subject, |
| 229 | Function<byte[], M> decoder, | 233 | Function<byte[], M> decoder, |
| ... | @@ -231,8 +235,26 @@ public class ClusterCommunicationManager | ... | @@ -231,8 +235,26 @@ public class ClusterCommunicationManager |
| 231 | Function<R, byte[]> encoder, | 235 | Function<R, byte[]> encoder, |
| 232 | Executor executor) { | 236 | Executor executor) { |
| 233 | messagingService.registerHandler(subject.value(), | 237 | messagingService.registerHandler(subject.value(), |
| 234 | - new InternalMessageResponder<>(decoder, encoder, handler), | 238 | + new InternalMessageResponder<M, R>(decoder, encoder, m -> { |
| 235 | - executor); | 239 | + CompletableFuture<R> responseFuture = new CompletableFuture<>(); |
| 240 | + executor.execute(() -> { | ||
| 241 | + try { | ||
| 242 | + responseFuture.complete(handler.apply(m)); | ||
| 243 | + } catch (Exception e) { | ||
| 244 | + responseFuture.completeExceptionally(e); | ||
| 245 | + } | ||
| 246 | + }); | ||
| 247 | + return responseFuture; | ||
| 248 | + })); | ||
| 249 | + } | ||
| 250 | + | ||
| 251 | + @Override | ||
| 252 | + public <M, R> void addSubscriber(MessageSubject subject, | ||
| 253 | + Function<byte[], M> decoder, | ||
| 254 | + Function<M, CompletableFuture<R>> handler, | ||
| 255 | + Function<R, byte[]> encoder) { | ||
| 256 | + messagingService.registerHandler(subject.value(), | ||
| 257 | + new InternalMessageResponder<>(decoder, encoder, handler)); | ||
| 236 | } | 258 | } |
| 237 | 259 | ||
| 238 | @Override | 260 | @Override |
| ... | @@ -260,23 +282,22 @@ public class ClusterCommunicationManager | ... | @@ -260,23 +282,22 @@ public class ClusterCommunicationManager |
| 260 | } | 282 | } |
| 261 | } | 283 | } |
| 262 | 284 | ||
| 263 | - private class InternalMessageResponder<M, R> implements Function<byte[], byte[]> { | 285 | + private class InternalMessageResponder<M, R> implements Function<byte[], CompletableFuture<byte[]>> { |
| 264 | private final Function<byte[], M> decoder; | 286 | private final Function<byte[], M> decoder; |
| 265 | private final Function<R, byte[]> encoder; | 287 | private final Function<R, byte[]> encoder; |
| 266 | - private final Function<M, R> handler; | 288 | + private final Function<M, CompletableFuture<R>> handler; |
| 267 | 289 | ||
| 268 | public InternalMessageResponder(Function<byte[], M> decoder, | 290 | public InternalMessageResponder(Function<byte[], M> decoder, |
| 269 | Function<R, byte[]> encoder, | 291 | Function<R, byte[]> encoder, |
| 270 | - Function<M, R> handler) { | 292 | + Function<M, CompletableFuture<R>> handler) { |
| 271 | this.decoder = decoder; | 293 | this.decoder = decoder; |
| 272 | this.encoder = encoder; | 294 | this.encoder = encoder; |
| 273 | this.handler = handler; | 295 | this.handler = handler; |
| 274 | } | 296 | } |
| 275 | 297 | ||
| 276 | @Override | 298 | @Override |
| 277 | - public byte[] apply(byte[] bytes) { | 299 | + public CompletableFuture<byte[]> apply(byte[] bytes) { |
| 278 | - R reply = handler.apply(decoder.apply(ClusterMessage.fromBytes(bytes).payload())); | 300 | + return handler.apply(decoder.apply(ClusterMessage.fromBytes(bytes).payload())).thenApply(encoder); |
| 279 | - return encoder.apply(reply); | ||
| 280 | } | 301 | } |
| 281 | } | 302 | } |
| 282 | 303 | ... | ... |
| 1 | +package org.onosproject.store.consistent.impl; | ||
| 2 | + | ||
| 3 | +import java.net.URI; | ||
| 4 | +import java.nio.ByteBuffer; | ||
| 5 | +import java.util.concurrent.CompletableFuture; | ||
| 6 | + | ||
| 7 | +import org.onlab.util.Tools; | ||
| 8 | +import org.onosproject.cluster.ClusterService; | ||
| 9 | +import org.onosproject.cluster.ControllerNode; | ||
| 10 | +import org.onosproject.cluster.NodeId; | ||
| 11 | +import org.onosproject.store.cluster.messaging.ClusterCommunicationService; | ||
| 12 | +import org.onosproject.store.cluster.messaging.MessageSubject; | ||
| 13 | + | ||
| 14 | +import net.kuujo.copycat.protocol.AbstractProtocol; | ||
| 15 | +import net.kuujo.copycat.protocol.ProtocolClient; | ||
| 16 | +import net.kuujo.copycat.protocol.ProtocolHandler; | ||
| 17 | +import net.kuujo.copycat.protocol.ProtocolServer; | ||
| 18 | +import net.kuujo.copycat.util.Configurable; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * Protocol for Copycat communication that employs | ||
| 22 | + * {@code ClusterCommunicationService}. | ||
| 23 | + */ | ||
| 24 | +public class CopycatCommunicationProtocol extends AbstractProtocol { | ||
| 25 | + | ||
| 26 | + private static final MessageSubject COPYCAT_MESSAGE_SUBJECT = | ||
| 27 | + new MessageSubject("onos-copycat-message"); | ||
| 28 | + | ||
| 29 | + protected ClusterService clusterService; | ||
| 30 | + protected ClusterCommunicationService clusterCommunicator; | ||
| 31 | + | ||
| 32 | + public CopycatCommunicationProtocol(ClusterService clusterService, | ||
| 33 | + ClusterCommunicationService clusterCommunicator) { | ||
| 34 | + this.clusterService = clusterService; | ||
| 35 | + this.clusterCommunicator = clusterCommunicator; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + @Override | ||
| 39 | + public Configurable copy() { | ||
| 40 | + return this; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + @Override | ||
| 44 | + public ProtocolClient createClient(URI uri) { | ||
| 45 | + NodeId nodeId = uriToNodeId(uri); | ||
| 46 | + if (nodeId == null) { | ||
| 47 | + throw new IllegalStateException("Unknown peer " + uri); | ||
| 48 | + } | ||
| 49 | + return new Client(nodeId); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + @Override | ||
| 53 | + public ProtocolServer createServer(URI uri) { | ||
| 54 | + return new Server(); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + private class Server implements ProtocolServer { | ||
| 58 | + | ||
| 59 | + @Override | ||
| 60 | + public void handler(ProtocolHandler handler) { | ||
| 61 | + if (handler == null) { | ||
| 62 | + clusterCommunicator.removeSubscriber(COPYCAT_MESSAGE_SUBJECT); | ||
| 63 | + } else { | ||
| 64 | + clusterCommunicator.addSubscriber(COPYCAT_MESSAGE_SUBJECT, | ||
| 65 | + ByteBuffer::wrap, | ||
| 66 | + handler, | ||
| 67 | + Tools::byteBuffertoArray); | ||
| 68 | + // FIXME: Tools::byteBuffertoArray involves a array copy. | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + @Override | ||
| 73 | + public CompletableFuture<Void> listen() { | ||
| 74 | + return CompletableFuture.completedFuture(null); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + @Override | ||
| 78 | + public CompletableFuture<Void> close() { | ||
| 79 | + clusterCommunicator.removeSubscriber(COPYCAT_MESSAGE_SUBJECT); | ||
| 80 | + return CompletableFuture.completedFuture(null); | ||
| 81 | + } | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + private class Client implements ProtocolClient { | ||
| 85 | + private final NodeId peer; | ||
| 86 | + | ||
| 87 | + public Client(NodeId peer) { | ||
| 88 | + this.peer = peer; | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + @Override | ||
| 92 | + public CompletableFuture<ByteBuffer> write(ByteBuffer request) { | ||
| 93 | + return clusterCommunicator.sendAndReceive(request, | ||
| 94 | + COPYCAT_MESSAGE_SUBJECT, | ||
| 95 | + Tools::byteBuffertoArray, | ||
| 96 | + ByteBuffer::wrap, | ||
| 97 | + peer); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + @Override | ||
| 101 | + public CompletableFuture<Void> connect() { | ||
| 102 | + return CompletableFuture.completedFuture(null); | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + @Override | ||
| 106 | + public CompletableFuture<Void> close() { | ||
| 107 | + return CompletableFuture.completedFuture(null); | ||
| 108 | + } | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + private NodeId uriToNodeId(URI uri) { | ||
| 112 | + return clusterService.getNodes() | ||
| 113 | + .stream() | ||
| 114 | + .filter(node -> uri.getHost().equals(node.ip().toString())) | ||
| 115 | + .map(ControllerNode::id) | ||
| 116 | + .findAny() | ||
| 117 | + .orElse(null); | ||
| 118 | + } | ||
| 119 | +} |
| ... | @@ -107,7 +107,7 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -107,7 +107,7 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
| 107 | protected ClusterCommunicationService clusterCommunicator; | 107 | protected ClusterCommunicationService clusterCommunicator; |
| 108 | 108 | ||
| 109 | protected String nodeToUri(NodeInfo node) { | 109 | protected String nodeToUri(NodeInfo node) { |
| 110 | - return String.format("tcp://%s:%d", node.getIp(), COPYCAT_TCP_PORT); | 110 | + return String.format("onos://%s:%d", node.getIp(), node.getTcpPort()); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | @Activate | 113 | @Activate |
| ... | @@ -136,9 +136,10 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -136,9 +136,10 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
| 136 | .toArray(String[]::new); | 136 | .toArray(String[]::new); |
| 137 | 137 | ||
| 138 | String localNodeUri = nodeToUri(NodeInfo.of(clusterService.getLocalNode())); | 138 | String localNodeUri = nodeToUri(NodeInfo.of(clusterService.getLocalNode())); |
| 139 | + Protocol protocol = new CopycatCommunicationProtocol(clusterService, clusterCommunicator); | ||
| 139 | 140 | ||
| 140 | ClusterConfig clusterConfig = new ClusterConfig() | 141 | ClusterConfig clusterConfig = new ClusterConfig() |
| 141 | - .withProtocol(newNettyProtocol()) | 142 | + .withProtocol(protocol) |
| 142 | .withElectionTimeout(electionTimeoutMillis(activeNodeUris)) | 143 | .withElectionTimeout(electionTimeoutMillis(activeNodeUris)) |
| 143 | .withHeartbeatInterval(heartbeatTimeoutMillis(activeNodeUris)) | 144 | .withHeartbeatInterval(heartbeatTimeoutMillis(activeNodeUris)) |
| 144 | .withMembers(activeNodeUris) | 145 | .withMembers(activeNodeUris) |
| ... | @@ -232,6 +233,7 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -232,6 +233,7 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
| 232 | .collect(Collectors.toList()); | 233 | .collect(Collectors.toList()); |
| 233 | } | 234 | } |
| 234 | 235 | ||
| 236 | + @SuppressWarnings("unused") | ||
| 235 | private Protocol newNettyProtocol() { | 237 | private Protocol newNettyProtocol() { |
| 236 | return new NettyTcpProtocol() | 238 | return new NettyTcpProtocol() |
| 237 | .withSsl(false) | 239 | .withSsl(false) | ... | ... |
| ... | @@ -785,6 +785,12 @@ public class EventuallyConsistentMapImplTest { | ... | @@ -785,6 +785,12 @@ public class EventuallyConsistentMapImplTest { |
| 785 | } | 785 | } |
| 786 | 786 | ||
| 787 | @Override | 787 | @Override |
| 788 | + public <M, R> void addSubscriber(MessageSubject subject, | ||
| 789 | + Function<byte[], M> decoder, Function<M, CompletableFuture<R>> handler, | ||
| 790 | + Function<R, byte[]> encoder) { | ||
| 791 | + } | ||
| 792 | + | ||
| 793 | + @Override | ||
| 788 | public <M> void addSubscriber(MessageSubject subject, | 794 | public <M> void addSubscriber(MessageSubject subject, |
| 789 | Function<byte[], M> decoder, Consumer<M> handler, | 795 | Function<byte[], M> decoder, Consumer<M> handler, |
| 790 | Executor executor) { | 796 | Executor executor) { | ... | ... |
| ... | @@ -22,7 +22,7 @@ def get_OC_vars(): | ... | @@ -22,7 +22,7 @@ def get_OC_vars(): |
| 22 | vars.append(var) | 22 | vars.append(var) |
| 23 | return sorted(vars, key=alphanum_key) | 23 | return sorted(vars, key=alphanum_key) |
| 24 | 24 | ||
| 25 | -def get_nodes(vars, port=7238): | 25 | +def get_nodes(vars, port=9876): |
| 26 | node = lambda k: { 'id': k, 'ip': k, 'tcpPort': port } | 26 | node = lambda k: { 'id': k, 'ip': k, 'tcpPort': port } |
| 27 | return [ node(environ[v]) for v in vars ] | 27 | return [ node(environ[v]) for v in vars ] |
| 28 | 28 | ... | ... |
| ... | @@ -25,6 +25,7 @@ import java.io.File; | ... | @@ -25,6 +25,7 @@ import java.io.File; |
| 25 | import java.io.FileInputStream; | 25 | import java.io.FileInputStream; |
| 26 | import java.io.IOException; | 26 | import java.io.IOException; |
| 27 | import java.io.InputStreamReader; | 27 | import java.io.InputStreamReader; |
| 28 | +import java.nio.ByteBuffer; | ||
| 28 | import java.nio.charset.StandardCharsets; | 29 | import java.nio.charset.StandardCharsets; |
| 29 | import java.nio.file.FileVisitResult; | 30 | import java.nio.file.FileVisitResult; |
| 30 | import java.nio.file.Files; | 31 | import java.nio.file.Files; |
| ... | @@ -34,9 +35,11 @@ import java.nio.file.SimpleFileVisitor; | ... | @@ -34,9 +35,11 @@ import java.nio.file.SimpleFileVisitor; |
| 34 | import java.nio.file.StandardCopyOption; | 35 | import java.nio.file.StandardCopyOption; |
| 35 | import java.nio.file.attribute.BasicFileAttributes; | 36 | import java.nio.file.attribute.BasicFileAttributes; |
| 36 | import java.util.ArrayList; | 37 | import java.util.ArrayList; |
| 38 | +import java.util.Arrays; | ||
| 37 | import java.util.Collection; | 39 | import java.util.Collection; |
| 38 | import java.util.Dictionary; | 40 | import java.util.Dictionary; |
| 39 | import java.util.List; | 41 | import java.util.List; |
| 42 | +import java.util.concurrent.CompletableFuture; | ||
| 40 | import java.util.concurrent.ExecutionException; | 43 | import java.util.concurrent.ExecutionException; |
| 41 | import java.util.concurrent.Future; | 44 | import java.util.concurrent.Future; |
| 42 | import java.util.concurrent.ThreadFactory; | 45 | import java.util.concurrent.ThreadFactory; |
| ... | @@ -388,6 +391,37 @@ public abstract class Tools { | ... | @@ -388,6 +391,37 @@ public abstract class Tools { |
| 388 | } | 391 | } |
| 389 | } | 392 | } |
| 390 | 393 | ||
| 394 | + /** | ||
| 395 | + * Returns a future that is completed exceptionally. | ||
| 396 | + * @param t exception | ||
| 397 | + * @param <T> future value type | ||
| 398 | + * @return future | ||
| 399 | + */ | ||
| 400 | + public static <T> CompletableFuture<T> exceptionalFuture(Throwable t) { | ||
| 401 | + CompletableFuture<T> future = new CompletableFuture<>(); | ||
| 402 | + future.completeExceptionally(t); | ||
| 403 | + return future; | ||
| 404 | + } | ||
| 405 | + | ||
| 406 | + /** | ||
| 407 | + * Returns the contents of {@code ByteBuffer} as byte array. | ||
| 408 | + * <p> | ||
| 409 | + * WARNING: There is a performance cost due to array copy | ||
| 410 | + * when using this method. | ||
| 411 | + * @param buffer byte buffer | ||
| 412 | + * @return byte array containing the byte buffer contents | ||
| 413 | + */ | ||
| 414 | + public static byte[] byteBuffertoArray(ByteBuffer buffer) { | ||
| 415 | + int length = buffer.remaining(); | ||
| 416 | + if (buffer.hasArray()) { | ||
| 417 | + int offset = buffer.arrayOffset() + buffer.position(); | ||
| 418 | + return Arrays.copyOfRange(buffer.array(), offset, offset + length); | ||
| 419 | + } | ||
| 420 | + byte[] bytes = new byte[length]; | ||
| 421 | + buffer.duplicate().get(bytes); | ||
| 422 | + return bytes; | ||
| 423 | + } | ||
| 424 | + | ||
| 391 | // Auxiliary path visitor for recursive directory structure copying. | 425 | // Auxiliary path visitor for recursive directory structure copying. |
| 392 | private static class DirectoryCopier extends SimpleFileVisitor<Path> { | 426 | private static class DirectoryCopier extends SimpleFileVisitor<Path> { |
| 393 | private Path src; | 427 | private Path src; | ... | ... |
| ... | @@ -203,6 +203,25 @@ public class NettyMessaging implements MessagingService { | ... | @@ -203,6 +203,25 @@ public class NettyMessaging implements MessagingService { |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | @Override | 205 | @Override |
| 206 | + public void registerHandler(String type, Function<byte[], CompletableFuture<byte[]>> handler) { | ||
| 207 | + handlers.put(type, message -> { | ||
| 208 | + handler.apply(message.payload()).whenComplete((result, error) -> { | ||
| 209 | + if (error == null) { | ||
| 210 | + InternalMessage response = new InternalMessage(message.id(), | ||
| 211 | + localEp, | ||
| 212 | + REPLY_MESSAGE_TYPE, | ||
| 213 | + result); | ||
| 214 | + try { | ||
| 215 | + sendAsync(message.sender(), response); | ||
| 216 | + } catch (IOException e) { | ||
| 217 | + log.debug("Failed to respond", e); | ||
| 218 | + } | ||
| 219 | + } | ||
| 220 | + }); | ||
| 221 | + }); | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + @Override | ||
| 206 | public void unregisterHandler(String type) { | 225 | public void unregisterHandler(String type) { |
| 207 | handlers.remove(type); | 226 | handlers.remove(type); |
| 208 | } | 227 | } | ... | ... |
| ... | @@ -212,6 +212,23 @@ public class IOLoopMessaging implements MessagingService { | ... | @@ -212,6 +212,23 @@ public class IOLoopMessaging implements MessagingService { |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | @Override | 214 | @Override |
| 215 | + public void registerHandler(String type, Function<byte[], CompletableFuture<byte[]>> handler) { | ||
| 216 | + handlers.put(type, message -> handler.apply(message.payload()).whenComplete((result, error) -> { | ||
| 217 | + if (error == null) { | ||
| 218 | + DefaultMessage response = new DefaultMessage(message.id(), | ||
| 219 | + localEp, | ||
| 220 | + REPLY_MESSAGE_TYPE, | ||
| 221 | + result); | ||
| 222 | + try { | ||
| 223 | + sendAsync(message.sender(), response); | ||
| 224 | + } catch (IOException e) { | ||
| 225 | + log.debug("Failed to respond", e); | ||
| 226 | + } | ||
| 227 | + } | ||
| 228 | + })); | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + @Override | ||
| 215 | public void unregisterHandler(String type) { | 232 | public void unregisterHandler(String type) { |
| 216 | handlers.remove(type); | 233 | handlers.remove(type); |
| 217 | } | 234 | } |
| ... | @@ -312,4 +329,4 @@ public class IOLoopMessaging implements MessagingService { | ... | @@ -312,4 +329,4 @@ public class IOLoopMessaging implements MessagingService { |
| 312 | return stream.isClosed(); | 329 | return stream.isClosed(); |
| 313 | } | 330 | } |
| 314 | } | 331 | } |
| 315 | -} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 332 | +} | ... | ... |
-
Please register or login to post a comment