Added a messaging service implementation on top of IOLoop. Added ability to easi…
…ly switch between netty and io loop (default is netty) Change-Id: Id9af0756bf0a542f832f3611b486b2ac680b91e4
Showing
25 changed files
with
483 additions
and
403 deletions
... | @@ -15,7 +15,6 @@ | ... | @@ -15,7 +15,6 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.store.cluster.messaging; | 16 | package org.onosproject.store.cluster.messaging; |
17 | 17 | ||
18 | -import java.io.IOException; | ||
19 | import java.nio.ByteBuffer; | 18 | import java.nio.ByteBuffer; |
20 | import java.util.Arrays; | 19 | import java.util.Arrays; |
21 | import java.util.Objects; | 20 | import java.util.Objects; |
... | @@ -35,6 +34,7 @@ public class ClusterMessage { | ... | @@ -35,6 +34,7 @@ public class ClusterMessage { |
35 | private final NodeId sender; | 34 | private final NodeId sender; |
36 | private final MessageSubject subject; | 35 | private final MessageSubject subject; |
37 | private final byte[] payload; | 36 | private final byte[] payload; |
37 | + private transient byte[] response; | ||
38 | 38 | ||
39 | /** | 39 | /** |
40 | * Creates a cluster message. | 40 | * Creates a cluster message. |
... | @@ -77,13 +77,21 @@ public class ClusterMessage { | ... | @@ -77,13 +77,21 @@ public class ClusterMessage { |
77 | } | 77 | } |
78 | 78 | ||
79 | /** | 79 | /** |
80 | - * Sends a response to the sender. | 80 | + * Records the response to be sent to the sender. |
81 | * | 81 | * |
82 | - * @param data payload response. | 82 | + * @param data response payload |
83 | - * @throws IOException when I/O exception of some sort has occurred | ||
84 | */ | 83 | */ |
85 | - public void respond(byte[] data) throws IOException { | 84 | + public void respond(byte[] data) { |
86 | - throw new IllegalStateException("One can only respond to message received from others."); | 85 | + response = data; |
86 | + } | ||
87 | + | ||
88 | + /** | ||
89 | + * Returns the response to be sent to the sender. | ||
90 | + * | ||
91 | + * @return response bytes | ||
92 | + */ | ||
93 | + public byte[] response() { | ||
94 | + return response; | ||
87 | } | 95 | } |
88 | 96 | ||
89 | @Override | 97 | @Override | ... | ... |
... | @@ -13,9 +13,9 @@ | ... | @@ -13,9 +13,9 @@ |
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.onlab.netty; | 16 | +package org.onosproject.store.cluster.messaging; |
17 | 17 | ||
18 | -import static com.google.common.base.Preconditions.*; | 18 | +import static com.google.common.base.Preconditions.checkNotNull; |
19 | 19 | ||
20 | import java.util.Objects; | 20 | import java.util.Objects; |
21 | 21 | ... | ... |
... | @@ -13,16 +13,19 @@ | ... | @@ -13,16 +13,19 @@ |
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.onlab.netty; | 16 | +package org.onosproject.store.cluster.messaging; |
17 | 17 | ||
18 | import java.io.IOException; | 18 | import java.io.IOException; |
19 | import java.util.concurrent.CompletableFuture; | 19 | import java.util.concurrent.CompletableFuture; |
20 | import java.util.concurrent.Executor; | 20 | import java.util.concurrent.Executor; |
21 | +import java.util.function.Consumer; | ||
22 | +import java.util.function.Function; | ||
21 | 23 | ||
22 | /** | 24 | /** |
23 | * Interface for low level messaging primitives. | 25 | * Interface for low level messaging primitives. |
24 | */ | 26 | */ |
25 | public interface MessagingService { | 27 | public interface MessagingService { |
28 | + | ||
26 | /** | 29 | /** |
27 | * Sends a message asynchronously to the specified communication end point. | 30 | * Sends a message asynchronously to the specified communication end point. |
28 | * The message is specified using the type and payload. | 31 | * The message is specified using the type and payload. |
... | @@ -31,7 +34,7 @@ public interface MessagingService { | ... | @@ -31,7 +34,7 @@ public interface MessagingService { |
31 | * @param payload message payload bytes. | 34 | * @param payload message payload bytes. |
32 | * @throws IOException when I/O exception of some sort has occurred | 35 | * @throws IOException when I/O exception of some sort has occurred |
33 | */ | 36 | */ |
34 | - public void sendAsync(Endpoint ep, String type, byte[] payload) throws IOException; | 37 | + void sendAsync(Endpoint ep, String type, byte[] payload) throws IOException; |
35 | 38 | ||
36 | /** | 39 | /** |
37 | * Sends a message synchronously and waits for a response. | 40 | * Sends a message synchronously and waits for a response. |
... | @@ -40,7 +43,7 @@ public interface MessagingService { | ... | @@ -40,7 +43,7 @@ public interface MessagingService { |
40 | * @param payload message payload. | 43 | * @param payload message payload. |
41 | * @return a response future | 44 | * @return a response future |
42 | */ | 45 | */ |
43 | - public CompletableFuture<byte[]> sendAndReceive(Endpoint ep, String type, byte[] payload); | 46 | + CompletableFuture<byte[]> sendAndReceive(Endpoint ep, String type, byte[] payload); |
44 | 47 | ||
45 | /** | 48 | /** |
46 | * Registers a new message handler for message type. | 49 | * Registers a new message handler for message type. |
... | @@ -48,19 +51,19 @@ public interface MessagingService { | ... | @@ -48,19 +51,19 @@ public interface MessagingService { |
48 | * @param handler message handler | 51 | * @param handler message handler |
49 | * @param executor executor to use for running message handler logic. | 52 | * @param executor executor to use for running message handler logic. |
50 | */ | 53 | */ |
51 | - public void registerHandler(String type, MessageHandler handler, Executor executor); | 54 | + void registerHandler(String type, Consumer<byte[]> handler, Executor executor); |
52 | 55 | ||
53 | /** | 56 | /** |
54 | * Registers a new message handler for message type. | 57 | * Registers a new message handler for message type. |
55 | * @param type message type. | 58 | * @param type message type. |
56 | * @param handler message handler | 59 | * @param handler message handler |
60 | + * @param executor executor to use for running message handler logic. | ||
57 | */ | 61 | */ |
58 | - @Deprecated | 62 | + void registerHandler(String type, Function<byte[], byte[]> handler, Executor executor); |
59 | - public void registerHandler(String type, MessageHandler handler); | ||
60 | 63 | ||
61 | /** | 64 | /** |
62 | * Unregister current handler, if one exists for message type. | 65 | * Unregister current handler, if one exists for message type. |
63 | * @param type message type | 66 | * @param type message type |
64 | */ | 67 | */ |
65 | - public void unregisterHandler(String type); | 68 | + void unregisterHandler(String type); |
66 | } | 69 | } | ... | ... |
... | @@ -53,6 +53,12 @@ | ... | @@ -53,6 +53,12 @@ |
53 | 53 | ||
54 | <dependency> | 54 | <dependency> |
55 | <groupId>org.onosproject</groupId> | 55 | <groupId>org.onosproject</groupId> |
56 | + <artifactId>onlab-nio</artifactId> | ||
57 | + <version>${project.version}</version> | ||
58 | + </dependency> | ||
59 | + | ||
60 | + <dependency> | ||
61 | + <groupId>org.onosproject</groupId> | ||
56 | <artifactId>onlab-misc</artifactId> | 62 | <artifactId>onlab-misc</artifactId> |
57 | <version>${project.version}</version> | 63 | <version>${project.version}</version> |
58 | </dependency> | 64 | </dependency> | ... | ... |
... | @@ -19,14 +19,12 @@ import com.google.common.collect.ImmutableSet; | ... | @@ -19,14 +19,12 @@ import com.google.common.collect.ImmutableSet; |
19 | import com.google.common.collect.Maps; | 19 | import com.google.common.collect.Maps; |
20 | import com.google.common.collect.Sets; | 20 | import com.google.common.collect.Sets; |
21 | import com.hazelcast.util.AddressUtil; | 21 | import com.hazelcast.util.AddressUtil; |
22 | + | ||
22 | import org.apache.felix.scr.annotations.Activate; | 23 | import org.apache.felix.scr.annotations.Activate; |
23 | import org.apache.felix.scr.annotations.Component; | 24 | import org.apache.felix.scr.annotations.Component; |
24 | import org.apache.felix.scr.annotations.Deactivate; | 25 | import org.apache.felix.scr.annotations.Deactivate; |
25 | import org.apache.felix.scr.annotations.Service; | 26 | import org.apache.felix.scr.annotations.Service; |
26 | import org.joda.time.DateTime; | 27 | import org.joda.time.DateTime; |
27 | -import org.onlab.netty.Endpoint; | ||
28 | -import org.onlab.netty.Message; | ||
29 | -import org.onlab.netty.MessageHandler; | ||
30 | import org.onlab.netty.NettyMessagingService; | 28 | import org.onlab.netty.NettyMessagingService; |
31 | import org.onlab.packet.IpAddress; | 29 | import org.onlab.packet.IpAddress; |
32 | import org.onlab.util.KryoNamespace; | 30 | import org.onlab.util.KryoNamespace; |
... | @@ -38,6 +36,7 @@ import org.onosproject.cluster.ControllerNode.State; | ... | @@ -38,6 +36,7 @@ import org.onosproject.cluster.ControllerNode.State; |
38 | import org.onosproject.cluster.DefaultControllerNode; | 36 | import org.onosproject.cluster.DefaultControllerNode; |
39 | import org.onosproject.cluster.NodeId; | 37 | import org.onosproject.cluster.NodeId; |
40 | import org.onosproject.store.AbstractStore; | 38 | import org.onosproject.store.AbstractStore; |
39 | +import org.onosproject.store.cluster.messaging.Endpoint; | ||
41 | import org.onosproject.store.consistent.impl.DatabaseDefinition; | 40 | import org.onosproject.store.consistent.impl.DatabaseDefinition; |
42 | import org.onosproject.store.consistent.impl.DatabaseDefinitionStore; | 41 | import org.onosproject.store.consistent.impl.DatabaseDefinitionStore; |
43 | import org.onosproject.store.serializers.KryoNamespaces; | 42 | import org.onosproject.store.serializers.KryoNamespaces; |
... | @@ -56,6 +55,7 @@ import java.util.concurrent.ExecutorService; | ... | @@ -56,6 +55,7 @@ import java.util.concurrent.ExecutorService; |
56 | import java.util.concurrent.Executors; | 55 | import java.util.concurrent.Executors; |
57 | import java.util.concurrent.ScheduledExecutorService; | 56 | import java.util.concurrent.ScheduledExecutorService; |
58 | import java.util.concurrent.TimeUnit; | 57 | import java.util.concurrent.TimeUnit; |
58 | +import java.util.function.Consumer; | ||
59 | import java.util.stream.Collectors; | 59 | import java.util.stream.Collectors; |
60 | 60 | ||
61 | import static com.google.common.base.Preconditions.checkNotNull; | 61 | import static com.google.common.base.Preconditions.checkNotNull; |
... | @@ -108,7 +108,7 @@ public class DistributedClusterStore | ... | @@ -108,7 +108,7 @@ public class DistributedClusterStore |
108 | private final Map<NodeId, ControllerNode> allNodes = Maps.newConcurrentMap(); | 108 | private final Map<NodeId, ControllerNode> allNodes = Maps.newConcurrentMap(); |
109 | private final Map<NodeId, State> nodeStates = Maps.newConcurrentMap(); | 109 | private final Map<NodeId, State> nodeStates = Maps.newConcurrentMap(); |
110 | private final Map<NodeId, DateTime> nodeStateLastUpdatedTimes = Maps.newConcurrentMap(); | 110 | private final Map<NodeId, DateTime> nodeStateLastUpdatedTimes = Maps.newConcurrentMap(); |
111 | - private NettyMessagingService messagingService = new NettyMessagingService(); | 111 | + private NettyMessagingService messagingService; |
112 | private ScheduledExecutorService heartBeatSender = Executors.newSingleThreadScheduledExecutor( | 112 | private ScheduledExecutorService heartBeatSender = Executors.newSingleThreadScheduledExecutor( |
113 | groupedThreads("onos/cluster/membership", "heartbeat-sender")); | 113 | groupedThreads("onos/cluster/membership", "heartbeat-sender")); |
114 | private ExecutorService heartBeatMessageHandler = Executors.newSingleThreadExecutor( | 114 | private ExecutorService heartBeatMessageHandler = Executors.newSingleThreadExecutor( |
... | @@ -149,7 +149,6 @@ public class DistributedClusterStore | ... | @@ -149,7 +149,6 @@ public class DistributedClusterStore |
149 | establishSelfIdentity(); | 149 | establishSelfIdentity(); |
150 | 150 | ||
151 | messagingService = new NettyMessagingService(HEARTBEAT_FD_PORT); | 151 | messagingService = new NettyMessagingService(HEARTBEAT_FD_PORT); |
152 | - | ||
153 | try { | 152 | try { |
154 | messagingService.activate(); | 153 | messagingService.activate(); |
155 | } catch (InterruptedException e) { | 154 | } catch (InterruptedException e) { |
... | @@ -376,10 +375,10 @@ public class DistributedClusterStore | ... | @@ -376,10 +375,10 @@ public class DistributedClusterStore |
376 | throw new IllegalStateException("Unable to determine local ip"); | 375 | throw new IllegalStateException("Unable to determine local ip"); |
377 | } | 376 | } |
378 | 377 | ||
379 | - private class HeartbeatMessageHandler implements MessageHandler { | 378 | + private class HeartbeatMessageHandler implements Consumer<byte[]> { |
380 | @Override | 379 | @Override |
381 | - public void handle(Message message) throws IOException { | 380 | + public void accept(byte[] message) { |
382 | - HeartbeatMessage hb = SERIALIZER.decode(message.payload()); | 381 | + HeartbeatMessage hb = SERIALIZER.decode(message); |
383 | failureDetector.report(hb.source().id()); | 382 | failureDetector.report(hb.source().id()); |
384 | hb.knownPeers().forEach(node -> { | 383 | hb.knownPeers().forEach(node -> { |
385 | allNodes.put(node.id(), node); | 384 | allNodes.put(node.id(), node); | ... | ... |
... | @@ -21,18 +21,17 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -21,18 +21,17 @@ 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.netty.Endpoint; | ||
25 | -import org.onlab.netty.Message; | ||
26 | -import org.onlab.netty.MessageHandler; | ||
27 | -import org.onlab.netty.MessagingService; | ||
28 | import org.onlab.netty.NettyMessagingService; | 24 | import org.onlab.netty.NettyMessagingService; |
25 | +import org.onlab.nio.service.IOLoopMessagingService; | ||
29 | import org.onosproject.cluster.ClusterService; | 26 | import org.onosproject.cluster.ClusterService; |
30 | import org.onosproject.cluster.ControllerNode; | 27 | import org.onosproject.cluster.ControllerNode; |
31 | import org.onosproject.cluster.NodeId; | 28 | import org.onosproject.cluster.NodeId; |
32 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; | 29 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; |
33 | import org.onosproject.store.cluster.messaging.ClusterMessage; | 30 | import org.onosproject.store.cluster.messaging.ClusterMessage; |
34 | import org.onosproject.store.cluster.messaging.ClusterMessageHandler; | 31 | import org.onosproject.store.cluster.messaging.ClusterMessageHandler; |
32 | +import org.onosproject.store.cluster.messaging.Endpoint; | ||
35 | import org.onosproject.store.cluster.messaging.MessageSubject; | 33 | import org.onosproject.store.cluster.messaging.MessageSubject; |
34 | +import org.onosproject.store.cluster.messaging.MessagingService; | ||
36 | import org.slf4j.Logger; | 35 | import org.slf4j.Logger; |
37 | import org.slf4j.LoggerFactory; | 36 | import org.slf4j.LoggerFactory; |
38 | 37 | ||
... | @@ -64,17 +63,28 @@ public class ClusterCommunicationManager | ... | @@ -64,17 +63,28 @@ public class ClusterCommunicationManager |
64 | // TODO: This probably should not be a OSGi service. | 63 | // TODO: This probably should not be a OSGi service. |
65 | private MessagingService messagingService; | 64 | private MessagingService messagingService; |
66 | 65 | ||
66 | + private final boolean useNetty = true; | ||
67 | + | ||
67 | @Activate | 68 | @Activate |
68 | public void activate() { | 69 | public void activate() { |
69 | ControllerNode localNode = clusterService.getLocalNode(); | 70 | ControllerNode localNode = clusterService.getLocalNode(); |
70 | - NettyMessagingService netty = new NettyMessagingService(localNode.ip(), localNode.tcpPort()); | 71 | + if (useNetty) { |
71 | - // FIXME: workaround until it becomes a service. | 72 | + NettyMessagingService netty = new NettyMessagingService(localNode.ip(), localNode.tcpPort()); |
72 | - try { | 73 | + try { |
73 | - netty.activate(); | 74 | + netty.activate(); |
74 | - } catch (Exception e) { | 75 | + messagingService = netty; |
75 | - log.error("NettyMessagingService#activate", e); | 76 | + } catch (Exception e) { |
77 | + log.error("NettyMessagingService#activate", e); | ||
78 | + } | ||
79 | + } else { | ||
80 | + IOLoopMessagingService ioLoop = new IOLoopMessagingService(localNode.ip(), localNode.tcpPort()); | ||
81 | + try { | ||
82 | + ioLoop.activate(); | ||
83 | + messagingService = ioLoop; | ||
84 | + } catch (Exception e) { | ||
85 | + log.error("IOLoopMessagingService#activate", e); | ||
86 | + } | ||
76 | } | 87 | } |
77 | - messagingService = netty; | ||
78 | log.info("Started on {}:{}", localNode.ip(), localNode.tcpPort()); | 88 | log.info("Started on {}:{}", localNode.ip(), localNode.tcpPort()); |
79 | } | 89 | } |
80 | 90 | ||
... | @@ -83,9 +93,13 @@ public class ClusterCommunicationManager | ... | @@ -83,9 +93,13 @@ public class ClusterCommunicationManager |
83 | // TODO: cleanup messageingService if needed. | 93 | // TODO: cleanup messageingService if needed. |
84 | // FIXME: workaround until it becomes a service. | 94 | // FIXME: workaround until it becomes a service. |
85 | try { | 95 | try { |
86 | - ((NettyMessagingService) messagingService).deactivate(); | 96 | + if (useNetty) { |
97 | + ((NettyMessagingService) messagingService).deactivate(); | ||
98 | + } else { | ||
99 | + ((IOLoopMessagingService) messagingService).deactivate(); | ||
100 | + } | ||
87 | } catch (Exception e) { | 101 | } catch (Exception e) { |
88 | - log.error("NettyMessagingService#deactivate", e); | 102 | + log.error("MessagingService#deactivate", e); |
89 | } | 103 | } |
90 | log.info("Stopped"); | 104 | log.info("Stopped"); |
91 | } | 105 | } |
... | @@ -232,7 +246,9 @@ public class ClusterCommunicationManager | ... | @@ -232,7 +246,9 @@ public class ClusterCommunicationManager |
232 | public void addSubscriber(MessageSubject subject, | 246 | public void addSubscriber(MessageSubject subject, |
233 | ClusterMessageHandler subscriber, | 247 | ClusterMessageHandler subscriber, |
234 | ExecutorService executor) { | 248 | ExecutorService executor) { |
235 | - messagingService.registerHandler(subject.value(), new InternalClusterMessageHandler(subscriber), executor); | 249 | + messagingService.registerHandler(subject.value(), |
250 | + new InternalClusterMessageHandler(subscriber), | ||
251 | + executor); | ||
236 | } | 252 | } |
237 | 253 | ||
238 | @Override | 254 | @Override |
... | @@ -240,31 +256,6 @@ public class ClusterCommunicationManager | ... | @@ -240,31 +256,6 @@ public class ClusterCommunicationManager |
240 | messagingService.unregisterHandler(subject.value()); | 256 | messagingService.unregisterHandler(subject.value()); |
241 | } | 257 | } |
242 | 258 | ||
243 | - private final class InternalClusterMessageHandler implements MessageHandler { | ||
244 | - | ||
245 | - private final ClusterMessageHandler handler; | ||
246 | - | ||
247 | - public InternalClusterMessageHandler(ClusterMessageHandler handler) { | ||
248 | - this.handler = handler; | ||
249 | - } | ||
250 | - | ||
251 | - @Override | ||
252 | - public void handle(Message message) { | ||
253 | - final ClusterMessage clusterMessage; | ||
254 | - try { | ||
255 | - clusterMessage = ClusterMessage.fromBytes(message.payload()); | ||
256 | - } catch (Exception e) { | ||
257 | - log.error("Failed decoding {}", message, e); | ||
258 | - throw e; | ||
259 | - } | ||
260 | - try { | ||
261 | - handler.handle(new InternalClusterMessage(clusterMessage, message)); | ||
262 | - } catch (Exception e) { | ||
263 | - log.trace("Failed handling {}", clusterMessage, e); | ||
264 | - throw e; | ||
265 | - } | ||
266 | - } | ||
267 | - } | ||
268 | 259 | ||
269 | @Override | 260 | @Override |
270 | public <M, R> void addSubscriber(MessageSubject subject, | 261 | public <M, R> void addSubscriber(MessageSubject subject, |
... | @@ -287,7 +278,22 @@ public class ClusterCommunicationManager | ... | @@ -287,7 +278,22 @@ public class ClusterCommunicationManager |
287 | executor); | 278 | executor); |
288 | } | 279 | } |
289 | 280 | ||
290 | - private class InternalMessageResponder<M, R> implements MessageHandler { | 281 | + private class InternalClusterMessageHandler implements Function<byte[], byte[]> { |
282 | + private ClusterMessageHandler handler; | ||
283 | + | ||
284 | + public InternalClusterMessageHandler(ClusterMessageHandler handler) { | ||
285 | + this.handler = handler; | ||
286 | + } | ||
287 | + | ||
288 | + @Override | ||
289 | + public byte[] apply(byte[] bytes) { | ||
290 | + ClusterMessage message = ClusterMessage.fromBytes(bytes); | ||
291 | + handler.handle(message); | ||
292 | + return message.response(); | ||
293 | + } | ||
294 | + } | ||
295 | + | ||
296 | + private class InternalMessageResponder<M, R> implements Function<byte[], byte[]> { | ||
291 | private final Function<byte[], M> decoder; | 297 | private final Function<byte[], M> decoder; |
292 | private final Function<R, byte[]> encoder; | 298 | private final Function<R, byte[]> encoder; |
293 | private final Function<M, R> handler; | 299 | private final Function<M, R> handler; |
... | @@ -299,14 +305,15 @@ public class ClusterCommunicationManager | ... | @@ -299,14 +305,15 @@ public class ClusterCommunicationManager |
299 | this.encoder = encoder; | 305 | this.encoder = encoder; |
300 | this.handler = handler; | 306 | this.handler = handler; |
301 | } | 307 | } |
308 | + | ||
302 | @Override | 309 | @Override |
303 | - public void handle(Message message) throws IOException { | 310 | + public byte[] apply(byte[] bytes) { |
304 | - R response = handler.apply(decoder.apply(ClusterMessage.fromBytes(message.payload()).payload())); | 311 | + R reply = handler.apply(decoder.apply(ClusterMessage.fromBytes(bytes).payload())); |
305 | - message.respond(encoder.apply(response)); | 312 | + return encoder.apply(reply); |
306 | } | 313 | } |
307 | } | 314 | } |
308 | 315 | ||
309 | - private class InternalMessageConsumer<M> implements MessageHandler { | 316 | + private class InternalMessageConsumer<M> implements Consumer<byte[]> { |
310 | private final Function<byte[], M> decoder; | 317 | private final Function<byte[], M> decoder; |
311 | private final Consumer<M> consumer; | 318 | private final Consumer<M> consumer; |
312 | 319 | ||
... | @@ -314,24 +321,10 @@ public class ClusterCommunicationManager | ... | @@ -314,24 +321,10 @@ public class ClusterCommunicationManager |
314 | this.decoder = decoder; | 321 | this.decoder = decoder; |
315 | this.consumer = consumer; | 322 | this.consumer = consumer; |
316 | } | 323 | } |
317 | - @Override | ||
318 | - public void handle(Message message) throws IOException { | ||
319 | - consumer.accept(decoder.apply(ClusterMessage.fromBytes(message.payload()).payload())); | ||
320 | - } | ||
321 | - } | ||
322 | - | ||
323 | - public static final class InternalClusterMessage extends ClusterMessage { | ||
324 | - | ||
325 | - private final Message rawMessage; | ||
326 | - | ||
327 | - public InternalClusterMessage(ClusterMessage clusterMessage, Message rawMessage) { | ||
328 | - super(clusterMessage.sender(), clusterMessage.subject(), clusterMessage.payload()); | ||
329 | - this.rawMessage = rawMessage; | ||
330 | - } | ||
331 | 324 | ||
332 | @Override | 325 | @Override |
333 | - public void respond(byte[] response) throws IOException { | 326 | + public void accept(byte[] bytes) { |
334 | - rawMessage.respond(response); | 327 | + consumer.accept(decoder.apply(ClusterMessage.fromBytes(bytes).payload())); |
335 | } | 328 | } |
336 | } | 329 | } |
337 | } | 330 | } | ... | ... |
... | @@ -77,7 +77,6 @@ import org.onosproject.store.serializers.impl.DistributedStoreSerializers; | ... | @@ -77,7 +77,6 @@ import org.onosproject.store.serializers.impl.DistributedStoreSerializers; |
77 | import org.osgi.service.component.ComponentContext; | 77 | import org.osgi.service.component.ComponentContext; |
78 | import org.slf4j.Logger; | 78 | import org.slf4j.Logger; |
79 | 79 | ||
80 | -import java.io.IOException; | ||
81 | import java.util.ArrayList; | 80 | import java.util.ArrayList; |
82 | import java.util.Arrays; | 81 | import java.util.Arrays; |
83 | import java.util.Collections; | 82 | import java.util.Collections; |
... | @@ -278,11 +277,7 @@ public class DistributedFlowRuleStore | ... | @@ -278,11 +277,7 @@ public class DistributedFlowRuleStore |
278 | FlowRule rule = SERIALIZER.decode(message.payload()); | 277 | FlowRule rule = SERIALIZER.decode(message.payload()); |
279 | log.trace("received get flow entry request for {}", rule); | 278 | log.trace("received get flow entry request for {}", rule); |
280 | FlowEntry flowEntry = flowTable.getFlowEntry(rule); //getFlowEntryInternal(rule); | 279 | FlowEntry flowEntry = flowTable.getFlowEntry(rule); //getFlowEntryInternal(rule); |
281 | - try { | 280 | + message.respond(SERIALIZER.encode(flowEntry)); |
282 | - message.respond(SERIALIZER.encode(flowEntry)); | ||
283 | - } catch (IOException e) { | ||
284 | - log.error("Failed to respond back", e); | ||
285 | - } | ||
286 | } | 281 | } |
287 | }, executor); | 282 | }, executor); |
288 | 283 | ||
... | @@ -293,11 +288,7 @@ public class DistributedFlowRuleStore | ... | @@ -293,11 +288,7 @@ public class DistributedFlowRuleStore |
293 | DeviceId deviceId = SERIALIZER.decode(message.payload()); | 288 | DeviceId deviceId = SERIALIZER.decode(message.payload()); |
294 | log.trace("Received get flow entries request for {} from {}", deviceId, message.sender()); | 289 | log.trace("Received get flow entries request for {} from {}", deviceId, message.sender()); |
295 | Set<FlowEntry> flowEntries = flowTable.getFlowEntries(deviceId); | 290 | Set<FlowEntry> flowEntries = flowTable.getFlowEntries(deviceId); |
296 | - try { | 291 | + message.respond(SERIALIZER.encode(flowEntries)); |
297 | - message.respond(SERIALIZER.encode(flowEntries)); | ||
298 | - } catch (IOException e) { | ||
299 | - log.error("Failed to respond to peer's getFlowEntries request", e); | ||
300 | - } | ||
301 | } | 292 | } |
302 | }, executor); | 293 | }, executor); |
303 | 294 | ||
... | @@ -308,11 +299,7 @@ public class DistributedFlowRuleStore | ... | @@ -308,11 +299,7 @@ public class DistributedFlowRuleStore |
308 | FlowEntry rule = SERIALIZER.decode(message.payload()); | 299 | FlowEntry rule = SERIALIZER.decode(message.payload()); |
309 | log.trace("received get flow entry request for {}", rule); | 300 | log.trace("received get flow entry request for {}", rule); |
310 | FlowRuleEvent event = removeFlowRuleInternal(rule); | 301 | FlowRuleEvent event = removeFlowRuleInternal(rule); |
311 | - try { | 302 | + message.respond(SERIALIZER.encode(event)); |
312 | - message.respond(SERIALIZER.encode(event)); | ||
313 | - } catch (IOException e) { | ||
314 | - log.error("Failed to respond back", e); | ||
315 | - } | ||
316 | } | 303 | } |
317 | }, executor); | 304 | }, executor); |
318 | } | 305 | } |
... | @@ -691,11 +678,7 @@ public class DistributedFlowRuleStore | ... | @@ -691,11 +678,7 @@ public class DistributedFlowRuleStore |
691 | // TODO: we might want to wrap response in envelope | 678 | // TODO: we might want to wrap response in envelope |
692 | // to distinguish sw programming failure and hand over | 679 | // to distinguish sw programming failure and hand over |
693 | // it make sense in the latter case to retry immediately. | 680 | // it make sense in the latter case to retry immediately. |
694 | - try { | 681 | + message.respond(SERIALIZER.encode(allFailed)); |
695 | - message.respond(SERIALIZER.encode(allFailed)); | ||
696 | - } catch (IOException e) { | ||
697 | - log.error("Failed to respond back", e); | ||
698 | - } | ||
699 | return; | 682 | return; |
700 | } | 683 | } |
701 | 684 | ... | ... |
... | @@ -51,7 +51,6 @@ import org.onosproject.store.serializers.StoreSerializer; | ... | @@ -51,7 +51,6 @@ import org.onosproject.store.serializers.StoreSerializer; |
51 | import org.onosproject.store.serializers.impl.DistributedStoreSerializers; | 51 | import org.onosproject.store.serializers.impl.DistributedStoreSerializers; |
52 | import org.slf4j.Logger; | 52 | import org.slf4j.Logger; |
53 | 53 | ||
54 | -import java.io.IOException; | ||
55 | import java.util.Collection; | 54 | import java.util.Collection; |
56 | import java.util.Collections; | 55 | import java.util.Collections; |
57 | import java.util.HashSet; | 56 | import java.util.HashSet; |
... | @@ -143,11 +142,7 @@ public class DefaultFlowRuleExtRouter | ... | @@ -143,11 +142,7 @@ public class DefaultFlowRuleExtRouter |
143 | @Override | 142 | @Override |
144 | public void run() { | 143 | public void run() { |
145 | FlowExtCompletedOperation result = Futures.getUnchecked(f); | 144 | FlowExtCompletedOperation result = Futures.getUnchecked(f); |
146 | - try { | 145 | + message.respond(SERIALIZER.encode(result)); |
147 | - message.respond(SERIALIZER.encode(result)); | ||
148 | - } catch (IOException e) { | ||
149 | - log.error("Failed to respond back", e); | ||
150 | - } | ||
151 | } | 146 | } |
152 | }, futureListeners); | 147 | }, futureListeners); |
153 | } | 148 | } | ... | ... |
... | @@ -22,7 +22,6 @@ import static org.onosproject.mastership.MastershipEvent.Type.MASTER_CHANGED; | ... | @@ -22,7 +22,6 @@ import static org.onosproject.mastership.MastershipEvent.Type.MASTER_CHANGED; |
22 | import static org.slf4j.LoggerFactory.getLogger; | 22 | import static org.slf4j.LoggerFactory.getLogger; |
23 | import static com.google.common.base.Preconditions.checkArgument; | 23 | import static com.google.common.base.Preconditions.checkArgument; |
24 | 24 | ||
25 | -import java.io.IOException; | ||
26 | import java.util.List; | 25 | import java.util.List; |
27 | import java.util.Map; | 26 | import java.util.Map; |
28 | import java.util.Set; | 27 | import java.util.Set; |
... | @@ -300,11 +299,7 @@ public class ConsistentDeviceMastershipStore | ... | @@ -300,11 +299,7 @@ public class ConsistentDeviceMastershipStore |
300 | @Override | 299 | @Override |
301 | public void handle(ClusterMessage message) { | 300 | public void handle(ClusterMessage message) { |
302 | DeviceId deviceId = SERIALIZER.decode(message.payload()); | 301 | DeviceId deviceId = SERIALIZER.decode(message.payload()); |
303 | - try { | 302 | + message.respond(SERIALIZER.encode(getRole(localNodeId, deviceId))); |
304 | - message.respond(SERIALIZER.encode(getRole(localNodeId, deviceId))); | ||
305 | - } catch (IOException e) { | ||
306 | - log.error("Failed to responsd to role query", e); | ||
307 | - } | ||
308 | } | 303 | } |
309 | } | 304 | } |
310 | 305 | ||
... | @@ -318,11 +313,7 @@ public class ConsistentDeviceMastershipStore | ... | @@ -318,11 +313,7 @@ public class ConsistentDeviceMastershipStore |
318 | @Override | 313 | @Override |
319 | public void handle(ClusterMessage message) { | 314 | public void handle(ClusterMessage message) { |
320 | DeviceId deviceId = SERIALIZER.decode(message.payload()); | 315 | DeviceId deviceId = SERIALIZER.decode(message.payload()); |
321 | - try { | 316 | + message.respond(SERIALIZER.encode(relinquishRole(localNodeId, deviceId))); |
322 | - message.respond(SERIALIZER.encode(relinquishRole(localNodeId, deviceId))); | ||
323 | - } catch (IOException e) { | ||
324 | - log.error("Failed to relinquish role.", e); | ||
325 | - } | ||
326 | } | 317 | } |
327 | } | 318 | } |
328 | 319 | ||
... | @@ -371,4 +362,4 @@ public class ConsistentDeviceMastershipStore | ... | @@ -371,4 +362,4 @@ public class ConsistentDeviceMastershipStore |
371 | return m.matches(); | 362 | return m.matches(); |
372 | } | 363 | } |
373 | 364 | ||
374 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
365 | +} | ... | ... |
... | @@ -43,7 +43,6 @@ import org.onosproject.store.serializers.KryoNamespaces; | ... | @@ -43,7 +43,6 @@ import org.onosproject.store.serializers.KryoNamespaces; |
43 | import org.onosproject.store.serializers.KryoSerializer; | 43 | import org.onosproject.store.serializers.KryoSerializer; |
44 | import org.slf4j.Logger; | 44 | import org.slf4j.Logger; |
45 | 45 | ||
46 | -import java.io.IOException; | ||
47 | import java.util.Collections; | 46 | import java.util.Collections; |
48 | import java.util.HashSet; | 47 | import java.util.HashSet; |
49 | import java.util.Map; | 48 | import java.util.Map; |
... | @@ -118,11 +117,7 @@ public class DistributedStatisticStore implements StatisticStore { | ... | @@ -118,11 +117,7 @@ public class DistributedStatisticStore implements StatisticStore { |
118 | @Override | 117 | @Override |
119 | public void handle(ClusterMessage message) { | 118 | public void handle(ClusterMessage message) { |
120 | ConnectPoint cp = SERIALIZER.decode(message.payload()); | 119 | ConnectPoint cp = SERIALIZER.decode(message.payload()); |
121 | - try { | 120 | + message.respond(SERIALIZER.encode(getCurrentStatisticInternal(cp))); |
122 | - message.respond(SERIALIZER.encode(getCurrentStatisticInternal(cp))); | ||
123 | - } catch (IOException e) { | ||
124 | - log.error("Failed to respond back", e); | ||
125 | - } | ||
126 | } | 121 | } |
127 | }, messageHandlingExecutor); | 122 | }, messageHandlingExecutor); |
128 | 123 | ||
... | @@ -131,11 +126,7 @@ public class DistributedStatisticStore implements StatisticStore { | ... | @@ -131,11 +126,7 @@ public class DistributedStatisticStore implements StatisticStore { |
131 | @Override | 126 | @Override |
132 | public void handle(ClusterMessage message) { | 127 | public void handle(ClusterMessage message) { |
133 | ConnectPoint cp = SERIALIZER.decode(message.payload()); | 128 | ConnectPoint cp = SERIALIZER.decode(message.payload()); |
134 | - try { | 129 | + message.respond(SERIALIZER.encode(getPreviousStatisticInternal(cp))); |
135 | - message.respond(SERIALIZER.encode(getPreviousStatisticInternal(cp))); | ||
136 | - } catch (IOException e) { | ||
137 | - log.error("Failed to respond back", e); | ||
138 | - } | ||
139 | } | 130 | } |
140 | }, messageHandlingExecutor); | 131 | }, messageHandlingExecutor); |
141 | log.info("Started"); | 132 | log.info("Started"); | ... | ... |
... | @@ -39,6 +39,10 @@ | ... | @@ -39,6 +39,10 @@ |
39 | </dependency> | 39 | </dependency> |
40 | <dependency> | 40 | <dependency> |
41 | <groupId>org.onosproject</groupId> | 41 | <groupId>org.onosproject</groupId> |
42 | + <artifactId>onos-api</artifactId> | ||
43 | + </dependency> | ||
44 | + <dependency> | ||
45 | + <groupId>org.onosproject</groupId> | ||
42 | <artifactId>onlab-misc</artifactId> | 46 | <artifactId>onlab-misc</artifactId> |
43 | </dependency> | 47 | </dependency> |
44 | <dependency> | 48 | <dependency> | ... | ... |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.netty; | ||
17 | - | ||
18 | -import java.io.IOException; | ||
19 | - | ||
20 | -import org.slf4j.Logger; | ||
21 | -import org.slf4j.LoggerFactory; | ||
22 | - | ||
23 | -//FIXME: Should be move out to test or app | ||
24 | -/** | ||
25 | - * Message handler that echos the message back to the sender. | ||
26 | - */ | ||
27 | -public class EchoHandler implements MessageHandler { | ||
28 | - | ||
29 | - private final Logger log = LoggerFactory.getLogger(getClass()); | ||
30 | - | ||
31 | - @Override | ||
32 | - public void handle(Message message) throws IOException { | ||
33 | - log.info("Received message. Echoing it back to the sender."); | ||
34 | - message.respond(message.payload()); | ||
35 | - } | ||
36 | -} |
... | @@ -15,9 +15,8 @@ | ... | @@ -15,9 +15,8 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.netty; | 16 | package org.onlab.netty; |
17 | 17 | ||
18 | -import java.io.IOException; | ||
19 | - | ||
20 | import org.onlab.util.ByteArraySizeHashPrinter; | 18 | import org.onlab.util.ByteArraySizeHashPrinter; |
19 | +import org.onosproject.store.cluster.messaging.Endpoint; | ||
21 | 20 | ||
22 | import com.google.common.base.MoreObjects; | 21 | import com.google.common.base.MoreObjects; |
23 | 22 | ||
... | @@ -25,20 +24,14 @@ import com.google.common.base.MoreObjects; | ... | @@ -25,20 +24,14 @@ import com.google.common.base.MoreObjects; |
25 | * Internal message representation with additional attributes | 24 | * Internal message representation with additional attributes |
26 | * for supporting, synchronous request/reply behavior. | 25 | * for supporting, synchronous request/reply behavior. |
27 | */ | 26 | */ |
28 | -public final class InternalMessage implements Message { | 27 | +public final class InternalMessage { |
29 | - | ||
30 | - public static final String REPLY_MESSAGE_TYPE = "NETTY_MESSAGING_REQUEST_REPLY"; | ||
31 | 28 | ||
32 | - private long id; | 29 | + private final long id; |
33 | - private Endpoint sender; | 30 | + private final Endpoint sender; |
34 | - private String type; | 31 | + private final String type; |
35 | - private byte[] payload; | 32 | + private final byte[] payload; |
36 | - private transient NettyMessagingService messagingService; | ||
37 | 33 | ||
38 | - // Must be created using the Builder. | 34 | + public InternalMessage(long id, Endpoint sender, String type, byte[] payload) { |
39 | - private InternalMessage() {} | ||
40 | - | ||
41 | - InternalMessage(long id, Endpoint sender, String type, byte[] payload) { | ||
42 | this.id = id; | 35 | this.id = id; |
43 | this.sender = sender; | 36 | this.sender = sender; |
44 | this.type = type; | 37 | this.type = type; |
... | @@ -57,26 +50,10 @@ public final class InternalMessage implements Message { | ... | @@ -57,26 +50,10 @@ public final class InternalMessage implements Message { |
57 | return sender; | 50 | return sender; |
58 | } | 51 | } |
59 | 52 | ||
60 | - @Override | ||
61 | public byte[] payload() { | 53 | public byte[] payload() { |
62 | return payload; | 54 | return payload; |
63 | } | 55 | } |
64 | 56 | ||
65 | - protected void setMessagingService(NettyMessagingService messagingService) { | ||
66 | - this.messagingService = messagingService; | ||
67 | - } | ||
68 | - | ||
69 | - @Override | ||
70 | - public void respond(byte[] data) throws IOException { | ||
71 | - Builder builder = new Builder(messagingService); | ||
72 | - InternalMessage message = builder.withId(this.id) | ||
73 | - .withSender(messagingService.localEp()) | ||
74 | - .withPayload(data) | ||
75 | - .withType(REPLY_MESSAGE_TYPE) | ||
76 | - .build(); | ||
77 | - messagingService.sendAsync(sender, message); | ||
78 | - } | ||
79 | - | ||
80 | @Override | 57 | @Override |
81 | public String toString() { | 58 | public String toString() { |
82 | return MoreObjects.toStringHelper(this) | 59 | return MoreObjects.toStringHelper(this) |
... | @@ -86,39 +63,4 @@ public final class InternalMessage implements Message { | ... | @@ -86,39 +63,4 @@ public final class InternalMessage implements Message { |
86 | .add("payload", ByteArraySizeHashPrinter.of(payload)) | 63 | .add("payload", ByteArraySizeHashPrinter.of(payload)) |
87 | .toString(); | 64 | .toString(); |
88 | } | 65 | } |
89 | - | ||
90 | - /** | ||
91 | - * Builder for InternalMessages. | ||
92 | - */ | ||
93 | - public static final class Builder { | ||
94 | - private InternalMessage message; | ||
95 | - | ||
96 | - public Builder(NettyMessagingService messagingService) { | ||
97 | - message = new InternalMessage(); | ||
98 | - message.messagingService = messagingService; | ||
99 | - } | ||
100 | - | ||
101 | - public Builder withId(long id) { | ||
102 | - message.id = id; | ||
103 | - return this; | ||
104 | - } | ||
105 | - | ||
106 | - public Builder withType(String type) { | ||
107 | - message.type = type; | ||
108 | - return this; | ||
109 | - } | ||
110 | - | ||
111 | - public Builder withSender(Endpoint sender) { | ||
112 | - message.sender = sender; | ||
113 | - return this; | ||
114 | - } | ||
115 | - public Builder withPayload(byte[] payload) { | ||
116 | - message.payload = payload; | ||
117 | - return this; | ||
118 | - } | ||
119 | - | ||
120 | - public InternalMessage build() { | ||
121 | - return message; | ||
122 | - } | ||
123 | - } | ||
124 | } | 66 | } | ... | ... |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.netty; | ||
17 | - | ||
18 | -import org.slf4j.Logger; | ||
19 | -import org.slf4j.LoggerFactory; | ||
20 | - | ||
21 | -/** | ||
22 | - * A MessageHandler that simply logs the information. | ||
23 | - */ | ||
24 | -public class LoggingHandler implements MessageHandler { | ||
25 | - | ||
26 | - private final Logger log = LoggerFactory.getLogger(getClass()); | ||
27 | - | ||
28 | - @Override | ||
29 | - public void handle(Message message) { | ||
30 | - log.info("Received message. Payload has {} bytes", message.payload().length); | ||
31 | - } | ||
32 | -} |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.netty; | ||
17 | - | ||
18 | -import java.io.IOException; | ||
19 | - | ||
20 | -/** | ||
21 | - * A unit of communication. | ||
22 | - * Has a payload. Also supports a feature to respond back to the sender. | ||
23 | - */ | ||
24 | -public interface Message { | ||
25 | - | ||
26 | - /** | ||
27 | - * Returns the payload of this message. | ||
28 | - * @return message payload. | ||
29 | - */ | ||
30 | - public byte[] payload(); | ||
31 | - | ||
32 | - /** | ||
33 | - * Sends a reply back to the sender of this message. | ||
34 | - * @param data payload of the response. | ||
35 | - * @throws IOException if there is a communication error. | ||
36 | - */ | ||
37 | - public void respond(byte[] data) throws IOException; | ||
38 | -} |
... | @@ -24,6 +24,7 @@ import java.util.List; | ... | @@ -24,6 +24,7 @@ import java.util.List; |
24 | 24 | ||
25 | import org.onlab.packet.IpAddress; | 25 | import org.onlab.packet.IpAddress; |
26 | import org.onlab.packet.IpAddress.Version; | 26 | import org.onlab.packet.IpAddress.Version; |
27 | +import org.onosproject.store.cluster.messaging.Endpoint; | ||
27 | import org.slf4j.Logger; | 28 | import org.slf4j.Logger; |
28 | import org.slf4j.LoggerFactory; | 29 | import org.slf4j.LoggerFactory; |
29 | 30 | ||
... | @@ -36,8 +37,6 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> { | ... | @@ -36,8 +37,6 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> { |
36 | 37 | ||
37 | private final Logger log = LoggerFactory.getLogger(getClass()); | 38 | private final Logger log = LoggerFactory.getLogger(getClass()); |
38 | 39 | ||
39 | - private final NettyMessagingService messagingService; | ||
40 | - | ||
41 | private long messageId; | 40 | private long messageId; |
42 | private Version ipVersion; | 41 | private Version ipVersion; |
43 | private IpAddress senderIp; | 42 | private IpAddress senderIp; |
... | @@ -46,9 +45,8 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> { | ... | @@ -46,9 +45,8 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> { |
46 | private String messageType; | 45 | private String messageType; |
47 | private int contentLength; | 46 | private int contentLength; |
48 | 47 | ||
49 | - public MessageDecoder(NettyMessagingService messagingService) { | 48 | + public MessageDecoder() { |
50 | super(DecoderState.READ_MESSAGE_ID); | 49 | super(DecoderState.READ_MESSAGE_ID); |
51 | - this.messagingService = messagingService; | ||
52 | } | 50 | } |
53 | 51 | ||
54 | @Override | 52 | @Override |
... | @@ -91,7 +89,6 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> { | ... | @@ -91,7 +89,6 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> { |
91 | new Endpoint(senderIp, senderPort), | 89 | new Endpoint(senderIp, senderPort), |
92 | messageType, | 90 | messageType, |
93 | payload); | 91 | payload); |
94 | - message.setMessagingService(messagingService); | ||
95 | out.add(message); | 92 | out.add(message); |
96 | checkpoint(DecoderState.READ_MESSAGE_ID); | 93 | checkpoint(DecoderState.READ_MESSAGE_ID); |
97 | break; | 94 | break; | ... | ... |
... | @@ -24,6 +24,7 @@ import java.io.IOException; | ... | @@ -24,6 +24,7 @@ import java.io.IOException; |
24 | 24 | ||
25 | import org.onlab.packet.IpAddress; | 25 | import org.onlab.packet.IpAddress; |
26 | import org.onlab.packet.IpAddress.Version; | 26 | import org.onlab.packet.IpAddress.Version; |
27 | +import org.onosproject.store.cluster.messaging.Endpoint; | ||
27 | import org.slf4j.Logger; | 28 | import org.slf4j.Logger; |
28 | import org.slf4j.LoggerFactory; | 29 | import org.slf4j.LoggerFactory; |
29 | 30 | ... | ... |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.netty; | ||
17 | - | ||
18 | -import java.io.IOException; | ||
19 | - | ||
20 | -/** | ||
21 | - * Handler for a message. | ||
22 | - */ | ||
23 | -public interface MessageHandler { | ||
24 | - | ||
25 | - /** | ||
26 | - * Handles the message. | ||
27 | - * | ||
28 | - * @param message message. | ||
29 | - * @throws IOException if an error is encountered handling the message | ||
30 | - */ | ||
31 | - public void handle(Message message) throws IOException; | ||
32 | -} |
... | @@ -46,10 +46,14 @@ import java.util.concurrent.Executor; | ... | @@ -46,10 +46,14 @@ import java.util.concurrent.Executor; |
46 | import java.util.concurrent.TimeUnit; | 46 | import java.util.concurrent.TimeUnit; |
47 | import java.util.concurrent.TimeoutException; | 47 | import java.util.concurrent.TimeoutException; |
48 | import java.util.concurrent.atomic.AtomicLong; | 48 | import java.util.concurrent.atomic.AtomicLong; |
49 | +import java.util.function.Consumer; | ||
50 | +import java.util.function.Function; | ||
49 | 51 | ||
50 | import org.apache.commons.pool.KeyedPoolableObjectFactory; | 52 | import org.apache.commons.pool.KeyedPoolableObjectFactory; |
51 | import org.apache.commons.pool.impl.GenericKeyedObjectPool; | 53 | import org.apache.commons.pool.impl.GenericKeyedObjectPool; |
52 | import org.onlab.packet.IpAddress; | 54 | import org.onlab.packet.IpAddress; |
55 | +import org.onosproject.store.cluster.messaging.Endpoint; | ||
56 | +import org.onosproject.store.cluster.messaging.MessagingService; | ||
53 | import org.slf4j.Logger; | 57 | import org.slf4j.Logger; |
54 | import org.slf4j.LoggerFactory; | 58 | import org.slf4j.LoggerFactory; |
55 | 59 | ||
... | @@ -59,17 +63,18 @@ import com.google.common.cache.RemovalListener; | ... | @@ -59,17 +63,18 @@ import com.google.common.cache.RemovalListener; |
59 | import com.google.common.cache.RemovalNotification; | 63 | import com.google.common.cache.RemovalNotification; |
60 | 64 | ||
61 | /** | 65 | /** |
62 | - * A Netty based implementation of MessagingService. | 66 | + * Implementation of MessagingService based on <a href="http://netty.io/">Netty</a> framework. |
63 | */ | 67 | */ |
64 | public class NettyMessagingService implements MessagingService { | 68 | public class NettyMessagingService implements MessagingService { |
65 | 69 | ||
66 | private final Logger log = LoggerFactory.getLogger(getClass()); | 70 | private final Logger log = LoggerFactory.getLogger(getClass()); |
67 | 71 | ||
72 | + private static final String REPLY_MESSAGE_TYPE = "NETTY_MESSAGING_REQUEST_REPLY"; | ||
73 | + | ||
68 | private final Endpoint localEp; | 74 | private final Endpoint localEp; |
69 | - private final ConcurrentMap<String, MessageHandler> handlers = new ConcurrentHashMap<>(); | 75 | + private final ConcurrentMap<String, Consumer<InternalMessage>> handlers = new ConcurrentHashMap<>(); |
70 | private final AtomicLong messageIdGenerator = new AtomicLong(0); | 76 | private final AtomicLong messageIdGenerator = new AtomicLong(0); |
71 | private final Cache<Long, CompletableFuture<byte[]>> responseFutures = CacheBuilder.newBuilder() | 77 | private final Cache<Long, CompletableFuture<byte[]>> responseFutures = CacheBuilder.newBuilder() |
72 | - .maximumSize(100000) | ||
73 | .expireAfterWrite(10, TimeUnit.SECONDS) | 78 | .expireAfterWrite(10, TimeUnit.SECONDS) |
74 | .removalListener(new RemovalListener<Long, CompletableFuture<byte[]>>() { | 79 | .removalListener(new RemovalListener<Long, CompletableFuture<byte[]>>() { |
75 | @Override | 80 | @Override |
... | @@ -124,6 +129,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -124,6 +129,7 @@ public class NettyMessagingService implements MessagingService { |
124 | } | 129 | } |
125 | 130 | ||
126 | public void activate() throws InterruptedException { | 131 | public void activate() throws InterruptedException { |
132 | + channels.setLifo(false); | ||
127 | channels.setTestOnBorrow(true); | 133 | channels.setTestOnBorrow(true); |
128 | channels.setTestOnReturn(true); | 134 | channels.setTestOnReturn(true); |
129 | initEventLoopGroup(); | 135 | initEventLoopGroup(); |
... | @@ -146,12 +152,10 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -146,12 +152,10 @@ public class NettyMessagingService implements MessagingService { |
146 | 152 | ||
147 | @Override | 153 | @Override |
148 | public void sendAsync(Endpoint ep, String type, byte[] payload) throws IOException { | 154 | public void sendAsync(Endpoint ep, String type, byte[] payload) throws IOException { |
149 | - InternalMessage message = new InternalMessage.Builder(this) | 155 | + InternalMessage message = new InternalMessage(messageIdGenerator.incrementAndGet(), |
150 | - .withId(messageIdGenerator.incrementAndGet()) | 156 | + localEp, |
151 | - .withSender(localEp) | 157 | + type, |
152 | - .withType(type) | 158 | + payload); |
153 | - .withPayload(payload) | ||
154 | - .build(); | ||
155 | sendAsync(ep, message); | 159 | sendAsync(ep, message); |
156 | } | 160 | } |
157 | 161 | ||
... | @@ -164,7 +168,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -164,7 +168,7 @@ public class NettyMessagingService implements MessagingService { |
164 | try { | 168 | try { |
165 | try { | 169 | try { |
166 | channel = channels.borrowObject(ep); | 170 | channel = channels.borrowObject(ep); |
167 | - channel.eventLoop().execute(new WriteTask(channel, message)); | 171 | + channel.writeAndFlush(message).addListener(ChannelFutureListener.CLOSE_ON_FAILURE); |
168 | } finally { | 172 | } finally { |
169 | channels.returnObject(ep, channel); | 173 | channels.returnObject(ep, channel); |
170 | } | 174 | } |
... | @@ -173,7 +177,6 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -173,7 +177,6 @@ public class NettyMessagingService implements MessagingService { |
173 | } catch (Exception e) { | 177 | } catch (Exception e) { |
174 | throw new IOException(e); | 178 | throw new IOException(e); |
175 | } | 179 | } |
176 | - | ||
177 | } | 180 | } |
178 | 181 | ||
179 | @Override | 182 | @Override |
... | @@ -181,12 +184,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -181,12 +184,7 @@ public class NettyMessagingService implements MessagingService { |
181 | CompletableFuture<byte[]> response = new CompletableFuture<>(); | 184 | CompletableFuture<byte[]> response = new CompletableFuture<>(); |
182 | Long messageId = messageIdGenerator.incrementAndGet(); | 185 | Long messageId = messageIdGenerator.incrementAndGet(); |
183 | responseFutures.put(messageId, response); | 186 | responseFutures.put(messageId, response); |
184 | - InternalMessage message = new InternalMessage.Builder(this) | 187 | + InternalMessage message = new InternalMessage(messageId, localEp, type, payload); |
185 | - .withId(messageId) | ||
186 | - .withSender(localEp) | ||
187 | - .withType(type) | ||
188 | - .withPayload(payload) | ||
189 | - .build(); | ||
190 | try { | 188 | try { |
191 | sendAsync(ep, message); | 189 | sendAsync(ep, message); |
192 | } catch (Exception e) { | 190 | } catch (Exception e) { |
... | @@ -197,24 +195,26 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -197,24 +195,26 @@ public class NettyMessagingService implements MessagingService { |
197 | } | 195 | } |
198 | 196 | ||
199 | @Override | 197 | @Override |
200 | - public void registerHandler(String type, MessageHandler handler) { | 198 | + public void registerHandler(String type, Consumer<byte[]> handler, Executor executor) { |
201 | - handlers.put(type, handler); | 199 | + handlers.put(type, message -> executor.execute(() -> handler.accept(message.payload()))); |
202 | } | 200 | } |
203 | 201 | ||
204 | @Override | 202 | @Override |
205 | - public void registerHandler(String type, MessageHandler handler, Executor executor) { | 203 | + public void registerHandler(String type, Function<byte[], byte[]> handler, Executor executor) { |
206 | - handlers.put(type, new MessageHandler() { | 204 | + handlers.put(type, message -> executor.execute(() -> { |
207 | - @Override | 205 | + byte[] responsePayload = handler.apply(message.payload()); |
208 | - public void handle(Message message) throws IOException { | 206 | + if (responsePayload != null) { |
209 | - executor.execute(() -> { | 207 | + InternalMessage response = new InternalMessage(message.id(), |
210 | - try { | 208 | + localEp, |
211 | - handler.handle(message); | 209 | + REPLY_MESSAGE_TYPE, |
212 | - } catch (Exception e) { | 210 | + responsePayload); |
213 | - log.debug("Failed to process message of type {}", type, e); | 211 | + try { |
214 | - } | 212 | + sendAsync(message.sender(), response); |
215 | - }); | 213 | + } catch (IOException e) { |
214 | + log.debug("Failed to respond", e); | ||
215 | + } | ||
216 | } | 216 | } |
217 | - }); | 217 | + })); |
218 | } | 218 | } |
219 | 219 | ||
220 | @Override | 220 | @Override |
... | @@ -222,14 +222,12 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -222,14 +222,12 @@ public class NettyMessagingService implements MessagingService { |
222 | handlers.remove(type); | 222 | handlers.remove(type); |
223 | } | 223 | } |
224 | 224 | ||
225 | - private MessageHandler getMessageHandler(String type) { | ||
226 | - return handlers.get(type); | ||
227 | - } | ||
228 | - | ||
229 | private void startAcceptingConnections() throws InterruptedException { | 225 | private void startAcceptingConnections() throws InterruptedException { |
230 | ServerBootstrap b = new ServerBootstrap(); | 226 | ServerBootstrap b = new ServerBootstrap(); |
231 | b.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024); | 227 | b.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024); |
232 | b.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 8 * 1024); | 228 | b.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 8 * 1024); |
229 | + b.option(ChannelOption.SO_RCVBUF, 1048576); | ||
230 | + b.option(ChannelOption.TCP_NODELAY, true); | ||
233 | b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); | 231 | b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); |
234 | b.group(serverGroup, clientGroup) | 232 | b.group(serverGroup, clientGroup) |
235 | .channel(serverChannelClass) | 233 | .channel(serverChannelClass) |
... | @@ -258,8 +256,9 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -258,8 +256,9 @@ public class NettyMessagingService implements MessagingService { |
258 | public Channel makeObject(Endpoint ep) throws Exception { | 256 | public Channel makeObject(Endpoint ep) throws Exception { |
259 | Bootstrap bootstrap = new Bootstrap(); | 257 | Bootstrap bootstrap = new Bootstrap(); |
260 | bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); | 258 | bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); |
261 | - bootstrap.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024); | 259 | + bootstrap.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 10 * 64 * 1024); |
262 | - bootstrap.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 8 * 1024); | 260 | + bootstrap.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 10 * 32 * 1024); |
261 | + bootstrap.option(ChannelOption.SO_SNDBUF, 1048576); | ||
263 | bootstrap.group(clientGroup); | 262 | bootstrap.group(clientGroup); |
264 | // TODO: Make this faster: | 263 | // TODO: Make this faster: |
265 | // http://normanmaurer.me/presentations/2014-facebook-eng-netty/slides.html#37.0 | 264 | // http://normanmaurer.me/presentations/2014-facebook-eng-netty/slides.html#37.0 |
... | @@ -268,6 +267,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -268,6 +267,7 @@ public class NettyMessagingService implements MessagingService { |
268 | bootstrap.handler(new OnosCommunicationChannelInitializer()); | 267 | bootstrap.handler(new OnosCommunicationChannelInitializer()); |
269 | // Start the client. | 268 | // Start the client. |
270 | ChannelFuture f = bootstrap.connect(ep.host().toString(), ep.port()).sync(); | 269 | ChannelFuture f = bootstrap.connect(ep.host().toString(), ep.port()).sync(); |
270 | + log.info("Established a new connection to {}", ep); | ||
271 | return f.channel(); | 271 | return f.channel(); |
272 | } | 272 | } |
273 | 273 | ||
... | @@ -291,27 +291,11 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -291,27 +291,11 @@ public class NettyMessagingService implements MessagingService { |
291 | protected void initChannel(SocketChannel channel) throws Exception { | 291 | protected void initChannel(SocketChannel channel) throws Exception { |
292 | channel.pipeline() | 292 | channel.pipeline() |
293 | .addLast("encoder", encoder) | 293 | .addLast("encoder", encoder) |
294 | - .addLast("decoder", new MessageDecoder(NettyMessagingService.this)) | 294 | + .addLast("decoder", new MessageDecoder()) |
295 | .addLast("handler", dispatcher); | 295 | .addLast("handler", dispatcher); |
296 | } | 296 | } |
297 | } | 297 | } |
298 | 298 | ||
299 | - private static class WriteTask implements Runnable { | ||
300 | - | ||
301 | - private final InternalMessage message; | ||
302 | - private final Channel channel; | ||
303 | - | ||
304 | - public WriteTask(Channel channel, InternalMessage message) { | ||
305 | - this.channel = channel; | ||
306 | - this.message = message; | ||
307 | - } | ||
308 | - | ||
309 | - @Override | ||
310 | - public void run() { | ||
311 | - channel.writeAndFlush(message).addListener(ChannelFutureListener.CLOSE_ON_FAILURE); | ||
312 | - } | ||
313 | - } | ||
314 | - | ||
315 | @ChannelHandler.Sharable | 299 | @ChannelHandler.Sharable |
316 | private class InboundMessageDispatcher extends SimpleChannelInboundHandler<InternalMessage> { | 300 | private class InboundMessageDispatcher extends SimpleChannelInboundHandler<InternalMessage> { |
317 | 301 | ||
... | @@ -329,10 +313,10 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -329,10 +313,10 @@ public class NettyMessagingService implements MessagingService { |
329 | 313 | ||
330 | private void dispatchLocally(InternalMessage message) throws IOException { | 314 | private void dispatchLocally(InternalMessage message) throws IOException { |
331 | String type = message.type(); | 315 | String type = message.type(); |
332 | - if (InternalMessage.REPLY_MESSAGE_TYPE.equals(type)) { | 316 | + if (REPLY_MESSAGE_TYPE.equals(type)) { |
333 | try { | 317 | try { |
334 | CompletableFuture<byte[]> futureResponse = | 318 | CompletableFuture<byte[]> futureResponse = |
335 | - NettyMessagingService.this.responseFutures.getIfPresent(message.id()); | 319 | + responseFutures.getIfPresent(message.id()); |
336 | if (futureResponse != null) { | 320 | if (futureResponse != null) { |
337 | futureResponse.complete(message.payload()); | 321 | futureResponse.complete(message.payload()); |
338 | } else { | 322 | } else { |
... | @@ -341,13 +325,13 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -341,13 +325,13 @@ public class NettyMessagingService implements MessagingService { |
341 | + " request handle", message.id(), message.sender()); | 325 | + " request handle", message.id(), message.sender()); |
342 | } | 326 | } |
343 | } finally { | 327 | } finally { |
344 | - NettyMessagingService.this.responseFutures.invalidate(message.id()); | 328 | + responseFutures.invalidate(message.id()); |
345 | } | 329 | } |
346 | return; | 330 | return; |
347 | } | 331 | } |
348 | - MessageHandler handler = NettyMessagingService.this.getMessageHandler(type); | 332 | + Consumer<InternalMessage> handler = handlers.get(type); |
349 | if (handler != null) { | 333 | if (handler != null) { |
350 | - handler.handle(message); | 334 | + handler.accept(message); |
351 | } else { | 335 | } else { |
352 | log.debug("No handler registered for {}", type); | 336 | log.debug("No handler registered for {}", type); |
353 | } | 337 | } | ... | ... |
... | @@ -18,13 +18,17 @@ package org.onlab.netty; | ... | @@ -18,13 +18,17 @@ package org.onlab.netty; |
18 | import static org.junit.Assert.assertArrayEquals; | 18 | import static org.junit.Assert.assertArrayEquals; |
19 | 19 | ||
20 | import java.net.InetAddress; | 20 | import java.net.InetAddress; |
21 | -import java.util.concurrent.Future; | 21 | +import java.util.concurrent.CompletableFuture; |
22 | import java.util.concurrent.TimeUnit; | 22 | import java.util.concurrent.TimeUnit; |
23 | +import java.util.function.Function; | ||
23 | 24 | ||
24 | import org.apache.commons.lang3.RandomUtils; | 25 | import org.apache.commons.lang3.RandomUtils; |
25 | import org.junit.Ignore; | 26 | import org.junit.Ignore; |
26 | import org.junit.Test; | 27 | import org.junit.Test; |
27 | import org.onlab.packet.IpAddress; | 28 | import org.onlab.packet.IpAddress; |
29 | +import org.onosproject.store.cluster.messaging.Endpoint; | ||
30 | + | ||
31 | +import com.google.common.util.concurrent.MoreExecutors; | ||
28 | 32 | ||
29 | /** | 33 | /** |
30 | * Simple ping-pong test that exercises NettyMessagingService. | 34 | * Simple ping-pong test that exercises NettyMessagingService. |
... | @@ -39,9 +43,9 @@ public class PingPongTest { | ... | @@ -39,9 +43,9 @@ public class PingPongTest { |
39 | try { | 43 | try { |
40 | pinger.activate(); | 44 | pinger.activate(); |
41 | ponger.activate(); | 45 | ponger.activate(); |
42 | - ponger.registerHandler("echo", new EchoHandler()); | 46 | + ponger.registerHandler("echo", Function.identity(), MoreExecutors.directExecutor()); |
43 | byte[] payload = RandomUtils.nextBytes(100); | 47 | byte[] payload = RandomUtils.nextBytes(100); |
44 | - Future<byte[]> responseFuture = | 48 | + CompletableFuture<byte[]> responseFuture = |
45 | pinger.sendAndReceive( | 49 | pinger.sendAndReceive( |
46 | new Endpoint(IpAddress.valueOf(InetAddress.getLocalHost()), 9086), "echo", payload); | 50 | new Endpoint(IpAddress.valueOf(InetAddress.getLocalHost()), 9086), "echo", payload); |
47 | assertArrayEquals(payload, responseFuture.get(10000, TimeUnit.MILLISECONDS)); | 51 | assertArrayEquals(payload, responseFuture.get(10000, TimeUnit.MILLISECONDS)); | ... | ... |
... | @@ -37,6 +37,14 @@ | ... | @@ -37,6 +37,14 @@ |
37 | <artifactId>guava-testlib</artifactId> | 37 | <artifactId>guava-testlib</artifactId> |
38 | <scope>test</scope> | 38 | <scope>test</scope> |
39 | </dependency> | 39 | </dependency> |
40 | + <dependency> | ||
41 | + <groupId>commons-pool</groupId> | ||
42 | + <artifactId>commons-pool</artifactId> | ||
43 | + </dependency> | ||
44 | + <dependency> | ||
45 | + <groupId>org.onosproject</groupId> | ||
46 | + <artifactId>onos-api</artifactId> | ||
47 | + </dependency> | ||
40 | <dependency> | 48 | <dependency> |
41 | <groupId>org.onosproject</groupId> | 49 | <groupId>org.onosproject</groupId> |
42 | <artifactId>onlab-misc</artifactId> | 50 | <artifactId>onlab-misc</artifactId> | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onlab.nio.service; | ||
17 | + | ||
18 | +import java.io.IOException; | ||
19 | +import java.nio.channels.ByteChannel; | ||
20 | +import java.nio.channels.SelectionKey; | ||
21 | +import java.util.List; | ||
22 | +import java.util.function.Consumer; | ||
23 | + | ||
24 | +import org.onlab.nio.IOLoop; | ||
25 | +import org.onlab.nio.MessageStream; | ||
26 | + | ||
27 | +/** | ||
28 | + * IOLoop for transporting DefaultMessages. | ||
29 | + */ | ||
30 | +public class DefaultIOLoop extends IOLoop<DefaultMessage, DefaultMessageStream> { | ||
31 | + | ||
32 | + public static final int SELECT_TIMEOUT_MILLIS = 500; | ||
33 | + private static final int MAX_IDLE_TIMEOUT_MILLIS = 1000; | ||
34 | + private static final int BUFFER_SIZE = 1024 * 1024; | ||
35 | + private final Consumer<DefaultMessage> consumer; | ||
36 | + | ||
37 | + public DefaultIOLoop(Consumer<DefaultMessage> consumer) throws IOException { | ||
38 | + this(SELECT_TIMEOUT_MILLIS, consumer); | ||
39 | + } | ||
40 | + | ||
41 | + public DefaultIOLoop(long timeout, Consumer<DefaultMessage> consumer) throws IOException { | ||
42 | + super(timeout); | ||
43 | + this.consumer = consumer; | ||
44 | + } | ||
45 | + | ||
46 | + @Override | ||
47 | + protected DefaultMessageStream createStream(ByteChannel byteChannel) { | ||
48 | + return new DefaultMessageStream(this, byteChannel, BUFFER_SIZE, MAX_IDLE_TIMEOUT_MILLIS); | ||
49 | + } | ||
50 | + | ||
51 | + @Override | ||
52 | + protected void processMessages(List<DefaultMessage> messages, MessageStream<DefaultMessage> stream) { | ||
53 | + messages.forEach(consumer); | ||
54 | + } | ||
55 | + | ||
56 | + @Override | ||
57 | + protected void connect(SelectionKey key) throws IOException { | ||
58 | + DefaultMessageStream stream = (DefaultMessageStream) key.attachment(); | ||
59 | + try { | ||
60 | + super.connect(key); | ||
61 | + stream.connected(); | ||
62 | + } catch (Exception e) { | ||
63 | + stream.connectFailed(e); | ||
64 | + } | ||
65 | + } | ||
66 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onlab.nio.service; | ||
17 | + | ||
18 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
19 | + | ||
20 | +import org.onlab.nio.AbstractMessage; | ||
21 | +import org.onlab.packet.IpAddress; | ||
22 | +import org.onlab.util.ByteArraySizeHashPrinter; | ||
23 | +import org.onosproject.store.cluster.messaging.Endpoint; | ||
24 | + | ||
25 | +import com.google.common.base.Charsets; | ||
26 | +import com.google.common.base.MoreObjects; | ||
27 | + | ||
28 | +/** | ||
29 | + * Default message. | ||
30 | + */ | ||
31 | +public class DefaultMessage extends AbstractMessage { | ||
32 | + | ||
33 | + private long id; | ||
34 | + private Endpoint sender; | ||
35 | + private String type; | ||
36 | + private byte[] payload; | ||
37 | + | ||
38 | + /** | ||
39 | + * Creates a new message with the specified data. | ||
40 | + * | ||
41 | + * @param id message id | ||
42 | + * @param type message type | ||
43 | + * @param sender sender endpoint | ||
44 | + * @param payload message payload | ||
45 | + */ | ||
46 | + DefaultMessage(long id, Endpoint sender, String type, byte[] payload) { | ||
47 | + this.id = id; | ||
48 | + this.type = checkNotNull(type, "Type cannot be null"); | ||
49 | + this.sender = checkNotNull(sender, "Sender cannot be null"); | ||
50 | + this.payload = checkNotNull(payload, "Payload cannot be null"); | ||
51 | + | ||
52 | + byte[] messageTypeBytes = type.getBytes(Charsets.UTF_8); | ||
53 | + IpAddress senderIp = sender.host(); | ||
54 | + byte[] ipOctets = senderIp.toOctets(); | ||
55 | + | ||
56 | + length = 25 + ipOctets.length + messageTypeBytes.length + payload.length; | ||
57 | + } | ||
58 | + | ||
59 | + /** | ||
60 | + * Returns message id. | ||
61 | + * | ||
62 | + * @return message id | ||
63 | + */ | ||
64 | + public long id() { | ||
65 | + return id; | ||
66 | + } | ||
67 | + | ||
68 | + /** | ||
69 | + * Returns message sender. | ||
70 | + * | ||
71 | + * @return message sender | ||
72 | + */ | ||
73 | + public Endpoint sender() { | ||
74 | + return sender; | ||
75 | + } | ||
76 | + | ||
77 | + /** | ||
78 | + * Returns message type. | ||
79 | + * | ||
80 | + * @return message type | ||
81 | + */ | ||
82 | + public String type() { | ||
83 | + return type; | ||
84 | + } | ||
85 | + | ||
86 | + /** | ||
87 | + * Returns message payload. | ||
88 | + * | ||
89 | + * @return payload | ||
90 | + */ | ||
91 | + public byte[] payload() { | ||
92 | + return payload; | ||
93 | + } | ||
94 | + | ||
95 | + @Override | ||
96 | + public String toString() { | ||
97 | + return MoreObjects.toStringHelper(this) | ||
98 | + .add("id", id) | ||
99 | + .add("type", type) | ||
100 | + .add("sender", sender) | ||
101 | + .add("payload", ByteArraySizeHashPrinter.of(payload)) | ||
102 | + .toString(); | ||
103 | + } | ||
104 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onlab.nio.service; | ||
17 | + | ||
18 | +import java.nio.ByteBuffer; | ||
19 | +import java.nio.channels.ByteChannel; | ||
20 | +import java.util.concurrent.CompletableFuture; | ||
21 | +import java.util.concurrent.atomic.AtomicInteger; | ||
22 | + | ||
23 | +import org.onlab.nio.IOLoop; | ||
24 | +import org.onlab.nio.MessageStream; | ||
25 | +import org.onlab.packet.IpAddress; | ||
26 | +import org.onlab.packet.IpAddress.Version; | ||
27 | +import org.onosproject.store.cluster.messaging.Endpoint; | ||
28 | + | ||
29 | +import com.google.common.base.Charsets; | ||
30 | + | ||
31 | +/** | ||
32 | + * Default bi-directional message stream for transferring messages to & from the | ||
33 | + * network via two byte buffers. | ||
34 | + */ | ||
35 | +public class DefaultMessageStream extends MessageStream<DefaultMessage> { | ||
36 | + | ||
37 | + private final CompletableFuture<Void> connectFuture = new CompletableFuture<>(); | ||
38 | + | ||
39 | + public DefaultMessageStream( | ||
40 | + IOLoop<DefaultMessage, ?> loop, | ||
41 | + ByteChannel byteChannel, | ||
42 | + int bufferSize, | ||
43 | + int maxIdleMillis) { | ||
44 | + super(loop, byteChannel, bufferSize, maxIdleMillis); | ||
45 | + } | ||
46 | + | ||
47 | + public CompletableFuture<DefaultMessageStream> connectedFuture() { | ||
48 | + return connectFuture.thenApply(v -> this); | ||
49 | + } | ||
50 | + | ||
51 | + private final AtomicInteger messageLength = new AtomicInteger(-1); | ||
52 | + | ||
53 | + @Override | ||
54 | + protected DefaultMessage read(ByteBuffer buffer) { | ||
55 | + if (messageLength.get() == -1) { | ||
56 | + // check if we can read the message length. | ||
57 | + if (buffer.remaining() < Integer.BYTES) { | ||
58 | + return null; | ||
59 | + } else { | ||
60 | + messageLength.set(buffer.getInt()); | ||
61 | + } | ||
62 | + } | ||
63 | + | ||
64 | + if (buffer.remaining() < messageLength.get()) { | ||
65 | + return null; | ||
66 | + } | ||
67 | + | ||
68 | + long id = buffer.getLong(); | ||
69 | + Version ipVersion = buffer.get() == 0x0 ? Version.INET : Version.INET6; | ||
70 | + byte[] octects = new byte[IpAddress.byteLength(ipVersion)]; | ||
71 | + buffer.get(octects); | ||
72 | + IpAddress senderIp = IpAddress.valueOf(ipVersion, octects); | ||
73 | + int senderPort = buffer.getInt(); | ||
74 | + int messageTypeByteLength = buffer.getInt(); | ||
75 | + byte[] messageTypeBytes = new byte[messageTypeByteLength]; | ||
76 | + buffer.get(messageTypeBytes); | ||
77 | + String messageType = new String(messageTypeBytes, Charsets.UTF_8); | ||
78 | + int payloadLength = buffer.getInt(); | ||
79 | + byte[] payloadBytes = new byte[payloadLength]; | ||
80 | + buffer.get(payloadBytes); | ||
81 | + | ||
82 | + // reset for next message | ||
83 | + messageLength.set(-1); | ||
84 | + | ||
85 | + return new DefaultMessage(id, new Endpoint(senderIp, senderPort), messageType, payloadBytes); | ||
86 | + } | ||
87 | + | ||
88 | + @Override | ||
89 | + protected void write(DefaultMessage message, ByteBuffer buffer) { | ||
90 | + Endpoint sender = message.sender(); | ||
91 | + byte[] messageTypeBytes = message.type().getBytes(Charsets.UTF_8); | ||
92 | + IpAddress senderIp = sender.host(); | ||
93 | + byte[] ipOctets = senderIp.toOctets(); | ||
94 | + byte[] payload = message.payload(); | ||
95 | + | ||
96 | + int messageLength = 21 + ipOctets.length + messageTypeBytes.length + payload.length; | ||
97 | + | ||
98 | + buffer.putInt(messageLength); | ||
99 | + | ||
100 | + buffer.putLong(message.id()); | ||
101 | + | ||
102 | + if (senderIp.version() == Version.INET) { | ||
103 | + buffer.put((byte) 0x0); | ||
104 | + } else { | ||
105 | + buffer.put((byte) 0x1); | ||
106 | + } | ||
107 | + buffer.put(ipOctets); | ||
108 | + | ||
109 | + // write sender port | ||
110 | + buffer.putInt(sender.port()); | ||
111 | + | ||
112 | + // write length of message type | ||
113 | + buffer.putInt(messageTypeBytes.length); | ||
114 | + | ||
115 | + // write message type bytes | ||
116 | + buffer.put(messageTypeBytes); | ||
117 | + | ||
118 | + // write payload length | ||
119 | + buffer.putInt(payload.length); | ||
120 | + | ||
121 | + // write payload. | ||
122 | + buffer.put(payload); | ||
123 | + } | ||
124 | + | ||
125 | + /** | ||
126 | + * Callback invoked when the stream is successfully connected. | ||
127 | + */ | ||
128 | + public void connected() { | ||
129 | + connectFuture.complete(null); | ||
130 | + } | ||
131 | + | ||
132 | + /** | ||
133 | + * Callback invoked when the stream fails to connect. | ||
134 | + * @param cause failure cause | ||
135 | + */ | ||
136 | + public void connectFailed(Throwable cause) { | ||
137 | + connectFuture.completeExceptionally(cause); | ||
138 | + } | ||
139 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment