connect();
81 |
82 | /**
83 | * Configures a received handler that gets notified when a STOMP frame is received by the client.
84 | * This handler can be used for logging, debugging or ad-hoc behavior. The frame can still be modified at the time.
85 | *
86 | * When a connection is created, the handler is used as
87 | * {@link StompClientConnection#receivedFrameHandler(Handler)}.
88 | *
89 | * @param handler the handler
90 | * @return the current {@link StompClient}
91 | */
92 | @Fluent
93 | StompClient receivedFrameHandler(Handler handler);
94 |
95 | /**
96 | * Configures a writing handler that gets notified when a STOMP frame is written on the wire.
97 | * This handler can be used for logging, debugging or ad-hoc behavior. The frame can still be modified at the time.
98 | *
99 | * When a connection is created, the handler is used as
100 | * {@link StompClientConnection#writingFrameHandler(Handler)}.
101 | *
102 | * @param handler the handler
103 | * @return the current {@link StompClient}
104 | */
105 | @Fluent
106 | StompClient writingFrameHandler(Handler handler);
107 |
108 | /**
109 | * A general error frame handler. It can be used to catch {@code ERROR} frame emitted during the connection process
110 | * (wrong authentication). This error handler will be pass to all {@link StompClientConnection} created from this
111 | * client. Obviously, the client can override it when the connection is established.
112 | *
113 | * @param handler the handler
114 | * @return the current {@link StompClient}
115 | */
116 | @Fluent
117 | StompClient errorFrameHandler(Handler handler);
118 |
119 | /**
120 | * Sets an exception handler notified for TCP-level errors.
121 | *
122 | * @param handler the handler
123 | * @return the current {@link StompClient}
124 | */
125 | @Fluent
126 | StompClient exceptionHandler(Handler handler);
127 |
128 | /**
129 | * Closes the client.
130 | */
131 | Future close();
132 |
133 | /**
134 | * @return the client's options.
135 | */
136 | StompClientOptions options();
137 |
138 | /**
139 | * @return the vert.x instance used by the client.
140 | */
141 | Vertx vertx();
142 |
143 | /**
144 | * @return whether or not the client is connected to the server.
145 | */
146 | boolean isClosed();
147 | }
148 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/StompOptions.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp;
18 |
19 | import io.vertx.core.json.JsonObject;
20 |
21 | import java.util.Arrays;
22 | import java.util.List;
23 |
24 | /**
25 | * Defines a couples of constants shared by client and server options.
26 | *
27 | * @author Clement Escoffier
28 | */
29 | public interface StompOptions {
30 |
31 | /**
32 | * UTF-8 encoding name.
33 | */
34 | String UTF_8 = "utf-8";
35 |
36 | int DEFAULT_STOMP_PORT = 61613;
37 | String DEFAULT_STOMP_HOST = "0.0.0.0";
38 | List DEFAULT_SUPPORTED_VERSIONS = Arrays.asList("1.2", "1.1", "1.0");
39 |
40 | JsonObject DEFAULT_STOMP_HEARTBEAT = new JsonObject().put("x", 1000).put("y", 1000);
41 |
42 | boolean DEFAULT_TRAILING_LINE = false;
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/StompServer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp;
18 |
19 | import io.vertx.codegen.annotations.Fluent;
20 | import io.vertx.codegen.annotations.VertxGen;
21 | import io.vertx.core.Future;
22 | import io.vertx.core.Handler;
23 | import io.vertx.core.Vertx;
24 | import io.vertx.core.http.ServerWebSocket;
25 | import io.vertx.core.http.ServerWebSocketHandshake;
26 | import io.vertx.core.net.NetServer;
27 | import io.vertx.ext.stomp.impl.StompServerImpl;
28 |
29 | /**
30 | * Defines a STOMP server. STOMP servers delegates to a {@link StompServerHandler} that let customize the behavior of
31 | * the server. By default, it uses a handler compliant with the STOMP specification, but let you change anything.
32 | *
33 | * @author Clement Escoffier
34 | */
35 | @VertxGen
36 | public interface StompServer {
37 |
38 | /**
39 | * Creates a {@link StompServer} based on the default Stomp Server implementation.
40 | *
41 | * @param vertx the vert.x instance to use
42 | * @param options the server options
43 | * @return the created {@link StompServer}
44 | */
45 | static StompServer create(Vertx vertx, StompServerOptions options) {
46 | return new StompServerImpl(vertx, null, options);
47 | }
48 |
49 | /**
50 | * Creates a {@link StompServer} based on the default Stomp Server implementation.
51 | *
52 | * @param vertx the vert.x instance to use
53 | * @param netServer the Net server used by the STOMP server
54 | * @return the created {@link StompServer}
55 | */
56 | static StompServer create(Vertx vertx, NetServer netServer) {
57 | return new StompServerImpl(vertx, netServer, new StompServerOptions());
58 | }
59 |
60 | /**
61 | * Creates a {@link StompServer} based on the default Stomp Server implementation.
62 | *
63 | * @param vertx the vert.x instance to use
64 | * @param net the Net server used by the STOMP server
65 | * @param options the server options
66 | * @return the created {@link StompServer}
67 | */
68 | static StompServer create(Vertx vertx, NetServer net, StompServerOptions options) {
69 | return new StompServerImpl(vertx, net, options);
70 | }
71 |
72 | /**
73 | * Creates a {@link StompServer} based on the default Stomp Server implementation, and use the default options.
74 | *
75 | * @param vertx the vert.x instance to use
76 | * @return the created {@link StompServer}
77 | */
78 | static StompServer create(Vertx vertx) {
79 | return create(vertx, new StompServerOptions());
80 | }
81 |
82 | /**
83 | * Configures the {@link StompServerHandler}. You must calls this method before calling the {@link #listen()} method.
84 | *
85 | * @param handler the handler
86 | * @return the current {@link StompServer}
87 | */
88 | @Fluent
89 | StompServer handler(StompServerHandler handler);
90 |
91 | /**
92 | * Connects the STOMP server to the given port. This method use the default host ({@code 0.0.0.0}). Once the socket
93 | * it bounds calls the given handler with the result. The result may be a failure if the socket is already used.
94 | *
95 | * @param port the port
96 | * @return a future resolved with the listen result
97 | */
98 | Future listen(int port);
99 |
100 | /**
101 | * Connects the STOMP server to the given port / interface. Once the socket it bounds calls the given handler with
102 | * the result. The result may be a failure if the socket is already used.
103 | *
104 | * @param port the port
105 | * @param host the interface
106 | * @return a future resolved with the listen result
107 | */
108 | Future listen(int port, String host);
109 |
110 | /**
111 | * Connects the STOMP server default port (61613) and network interface ({@code 0.0.0.0}). Once the socket
112 | * it bounds calls the given handler with the result. The result may be a failure if the socket is already used.
113 | *
114 | * @return a future resolved with the listen result
115 | */
116 | Future listen();
117 |
118 | /**
119 | * Closes the server.
120 | */
121 | Future close();
122 |
123 | /**
124 | * Checks whether or not the server is listening.
125 | *
126 | * @return {@code true} if the server is listening, {@code false} otherwise
127 | */
128 | boolean isListening();
129 |
130 | /**
131 | * Gets the port on which the server is listening.
132 | *
133 | * This is useful if you bound the server specifying 0 as port number signifying an ephemeral port.
134 | *
135 | * @return the port
136 | * @see NetServer#actualPort()
137 | */
138 | int actualPort();
139 |
140 | /**
141 | * @return the server options
142 | */
143 | StompServerOptions options();
144 |
145 | /**
146 | * @return the instance of vert.x used by the server.
147 | */
148 | Vertx vertx();
149 |
150 | /**
151 | * @return the {@link StompServerHandler} used by this server.
152 | */
153 | StompServerHandler stompHandler();
154 |
155 | /**
156 | * Gets the {@link Handler} able to manage web socket connection handshakes. If the web socket bridge is disabled, it returns
157 | * {@code null}.
158 | *
159 | * @return the handler that can be passed to {@link io.vertx.core.http.HttpServer#webSocketHandshakeHandler(Handler)}.
160 | */
161 | Handler webSocketHandshakeHandler();
162 |
163 | /**
164 | * Gets the {@link Handler} able to manage web socket connections. If the web socket bridge is disabled, it returns
165 | * {@code null}.
166 | *
167 | * @return the handler that can be passed to {@link io.vertx.core.http.HttpServer#webSocketHandler(Handler)}.
168 | */
169 | Handler webSocketHandler();
170 |
171 | /**
172 | * Configures the handler that is invoked every time a frame is going to be written to the "wire". It lets you log
173 | * the frames, but also adapt the frame if needed.
174 | *
175 | * @param handler the handler, must not be {@code null}
176 | * @return the current {@link StompServer}
177 | */
178 | @Fluent
179 | StompServer writingFrameHandler(Handler handler);
180 |
181 |
182 | }
183 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/StompServerConnection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp;
18 |
19 | import javax.net.ssl.SSLSession;
20 |
21 | import io.vertx.codegen.annotations.Fluent;
22 | import io.vertx.codegen.annotations.GenIgnore;
23 | import io.vertx.codegen.annotations.VertxGen;
24 | import io.vertx.core.Handler;
25 | import io.vertx.core.buffer.Buffer;
26 |
27 | /**
28 | * Class representing a connection between a STOMP client a the server. It keeps a references on the client socket,
29 | * so let write to this socket.
30 | *
31 | * @author Clement Escoffier
32 | */
33 | @VertxGen
34 | public interface StompServerConnection {
35 |
36 | /**
37 | * Writes the given frame to the socket.
38 | *
39 | * @param frame the frame, must not be {@code null}.
40 | * @return the current {@link StompServerConnection}
41 | */
42 | @Fluent
43 | StompServerConnection write(Frame frame);
44 |
45 | /**
46 | * Writes the given buffer to the socket. This is a low level API that should be used carefully.
47 | *
48 | * @param buffer the buffer
49 | * @return the current {@link StompServerConnection}
50 | */
51 | @Fluent
52 | StompServerConnection write(Buffer buffer);
53 |
54 | /**
55 | * @return the STOMP server serving this connection.
56 | */
57 | StompServer server();
58 |
59 | /**
60 | * @return SSLSession associated with the underlying socket. Returns null if connection is
61 | * not SSL.
62 | */
63 | @GenIgnore({"permitted-type"})
64 | SSLSession sslSession();
65 |
66 | /**
67 | * @return the STOMP server handler dealing with this connection
68 | */
69 | StompServerHandler handler();
70 |
71 | /**
72 | * @return the STOMP session id computed when the client has established the connection to the server
73 | */
74 | String session();
75 |
76 | /**
77 | * Closes the connection with the client.
78 | */
79 | void close();
80 |
81 | /**
82 | * Sends a `PING` frame to the client. A `PING` frame is a frame containing only {@code EOL}.
83 | */
84 | void ping();
85 |
86 | /**
87 | * Notifies the connection about server activity (the server has sent a frame). This method is used to handle the
88 | * heartbeat.
89 | */
90 | void onServerActivity();
91 |
92 | /**
93 | * Configures the heartbeat.
94 | * @param ping ping time
95 | * @param pong pong time
96 | * @param pingHandler the ping handler
97 | */
98 | void configureHeartbeat(long ping, long pong, Handler pingHandler);
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/impl/AcknowledgementImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp.impl;
18 |
19 | import io.vertx.codegen.annotations.VertxGen;
20 | import io.vertx.ext.stomp.Acknowledgement;
21 | import io.vertx.ext.stomp.Frame;
22 |
23 | import java.util.ArrayList;
24 | import java.util.List;
25 |
26 | /**
27 | * Basic implementation of {@link io.vertx.ext.stomp.Acknowledgement}.
28 | *
29 | * @author Clement Escoffier
30 | */
31 | @VertxGen
32 | public class AcknowledgementImpl implements Acknowledgement {
33 |
34 | private final Frame subscription;
35 | private final List frames;
36 |
37 | public AcknowledgementImpl(Frame subscription, List frames) {
38 | this.subscription = subscription;
39 | this.frames = new ArrayList<>(frames);
40 | }
41 |
42 | public Frame subscription() {
43 | return subscription;
44 | }
45 |
46 | public List frames() {
47 | return frames;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/impl/FrameException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp.impl;
18 |
19 | /**
20 | * Exception thrown when a STOMP frame is not structured correctly or does nto obey to the specification.
21 | *
22 | * This class is thread safe.
23 | *
24 | * @author Clement Escoffier
25 | */
26 | public class FrameException extends RuntimeException {
27 |
28 | public FrameException(String message) {
29 | super(message);
30 | }
31 |
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/impl/HeaderCodec.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp.impl;
18 |
19 | /**
20 | * Class responsible for the encoding and decoding of the STOMP frame headers.
21 | * This class is thread-safe.
22 | *
23 | * @author Clement Escoffier
24 | */
25 | public class HeaderCodec {
26 |
27 | private static final String ESCAPE_ESCAPE = String.valueOf(new char[]{(char) 92, (char) 92});
28 | private static final String COLON_ESCAPE = String.valueOf(new char[]{(char) 92, (char) 99});
29 | private static final String LINE_FEED_ESCAPE = String.valueOf(new char[]{(char) 92, (char) 110});
30 | private static final String CARRIAGE_RETURN_ESCAPE = String.valueOf(new char[]{(char) 92, (char) 114});
31 |
32 | private HeaderCodec() {
33 | //Avoid direct instantiation.
34 | }
35 |
36 | public static String encode(String header, boolean connectOrConnectedFrame) {
37 | StringBuilder builder = new StringBuilder();
38 |
39 | for (int i = 0; i < header.length(); i++) {
40 | char value = header.charAt(i);
41 | switch (value) {
42 | case FrameParser.ESCAPE:
43 | // Always encoded.
44 | builder.append(ESCAPE_ESCAPE);
45 | break;
46 | case FrameParser.LINE_FEED:
47 | if (connectOrConnectedFrame) {
48 | builder.append(value);
49 | } else {
50 | builder.append(LINE_FEED_ESCAPE);
51 | }
52 | break;
53 | case ':':
54 | if (connectOrConnectedFrame) {
55 | builder.append(value);
56 | } else {
57 | builder.append(COLON_ESCAPE);
58 | }
59 | break;
60 | case '\r':
61 | if (connectOrConnectedFrame) {
62 | builder.append(value);
63 | } else {
64 | builder.append(CARRIAGE_RETURN_ESCAPE);
65 | }
66 | break;
67 | default:
68 | builder.append(value);
69 | }
70 | }
71 | return builder.toString();
72 | }
73 |
74 | public static String decode(String header, boolean connectOrConnectedFrame) {
75 | StringBuilder builder = new StringBuilder();
76 |
77 | int i = 0;
78 | while (i < header.length()) {
79 | char value = header.charAt(i);
80 | if (value == 92 && i + 1 < header.length()) {
81 | char next = header.charAt(i + 1);
82 | switch (next) {
83 | case 114:
84 | if (connectOrConnectedFrame) {
85 | builder.append(value);
86 | } else {
87 | builder.append(FrameParser.CARRIAGE_RETURN);
88 | i++;
89 | }
90 | break;
91 | case 110:
92 | if (connectOrConnectedFrame) {
93 | builder.append(value);
94 | } else {
95 | builder.append(FrameParser.LINE_FEED);
96 | i++;
97 | }
98 | break;
99 | case 99:
100 | if (connectOrConnectedFrame) {
101 | builder.append(value);
102 | } else {
103 | builder.append(FrameParser.COLON);
104 | i++;
105 | }
106 | break;
107 | case 92:
108 | // Always decoded.
109 | builder.append(FrameParser.ESCAPE);
110 | i++;
111 | break;
112 | default:
113 | // By spec, all other escape must be treated as a fatal protocol error.
114 | throw new FrameException("Incorrect header value " +
115 | "- the header uses an illegal escaped character '" + next + "' (" + (byte) next + ")");
116 | }
117 | } else {
118 | builder.append(value);
119 | }
120 | i++;
121 | }
122 | return builder.toString();
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/impl/Queue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp.impl;
18 |
19 | import io.vertx.core.Vertx;
20 | import io.vertx.ext.stomp.Command;
21 | import io.vertx.ext.stomp.Destination;
22 | import io.vertx.ext.stomp.Frame;
23 | import io.vertx.ext.stomp.StompServerConnection;
24 | import io.vertx.ext.stomp.utils.Headers;
25 |
26 | import java.util.ArrayList;
27 | import java.util.List;
28 | import java.util.UUID;
29 | import java.util.stream.Collectors;
30 |
31 | /**
32 | * Implementation of {@link Destination} dispatching messages to a single subscriber. It dispatches
33 | * the messages using a round-robin strategy.
34 | *
35 | * @author Clement Escoffier
36 | */
37 | public class Queue implements Destination {
38 |
39 | private final String destination;
40 |
41 | private final List subscriptions = new ArrayList<>();
42 | private final Vertx vertx;
43 | private int lastUsedSubscriptions = -1;
44 |
45 | public Queue(Vertx vertx, String destination) {
46 | this.destination = destination;
47 | this.vertx = vertx;
48 | }
49 |
50 | /**
51 | * @return the destination address.
52 | */
53 | @Override
54 | public String destination() {
55 | return destination;
56 | }
57 |
58 | /**
59 | * Dispatches the given frame.
60 | *
61 | * @param connection the connection
62 | * @param frame the frame ({@code SEND} frame).
63 | * @return the current instance of {@link Destination}
64 | */
65 | @Override
66 | public synchronized Destination dispatch(StompServerConnection connection, Frame frame) {
67 | if (subscriptions.isEmpty()) {
68 | lastUsedSubscriptions = -1;
69 | return this;
70 | }
71 | Subscription subscription = getNextSubscription();
72 | String messageId = UUID.randomUUID().toString();
73 | Frame message = transform(frame, subscription, messageId);
74 | subscription.connection.write(message);
75 | return this;
76 | }
77 |
78 | private Subscription getNextSubscription() {
79 | lastUsedSubscriptions = lastUsedSubscriptions + 1;
80 | if (lastUsedSubscriptions >= subscriptions.size()) {
81 | lastUsedSubscriptions = 0;
82 | }
83 | return subscriptions.get(lastUsedSubscriptions);
84 | }
85 |
86 | public static Frame transform(Frame frame, Subscription subscription, String messageId) {
87 | final Headers headers = Headers.create(frame.getHeaders())
88 | // Destination already set in the input headers.
89 | .add(Frame.SUBSCRIPTION, subscription.id)
90 | .add(Frame.MESSAGE_ID, messageId);
91 | if (!subscription.ackMode.equals("auto")) {
92 | // We reuse the message Id as ack Id
93 | headers.add(Frame.ACK, messageId);
94 | }
95 | return new Frame(Command.MESSAGE,
96 | headers,
97 | frame.getBody());
98 | }
99 |
100 | /**
101 | * Handles a subscription request to the current {@link Destination}. All check about the frame format and unicity
102 | * of the id should have been done beforehand.
103 | *
104 | * @param connection the connection
105 | * @param frame the {@code SUBSCRIBE} frame
106 | * @return the current instance of {@link Destination}
107 | */
108 | @Override
109 | public synchronized Destination subscribe(StompServerConnection connection, Frame frame) {
110 | Subscription subscription = new Subscription(connection, frame);
111 | subscriptions.add(subscription);
112 | return this;
113 | }
114 |
115 | /**
116 | * Handles a un-subscription request to the current {@link Destination}.
117 | *
118 | * @param connection the connection
119 | * @param frame the {@code UNSUBSCRIBE} frame
120 | * @return {@code true} if the un-subscription has been handled, {@code false} otherwise.
121 | */
122 | @Override
123 | public synchronized boolean unsubscribe(StompServerConnection connection, Frame frame) {
124 | boolean r = false;
125 | for (Subscription subscription : subscriptions) {
126 | if (subscription.connection.equals(connection) && subscription.id.equals(frame.getId())) {
127 | r = subscriptions.remove(subscription);
128 | // Subscription id are unique for a connection.
129 | break;
130 | }
131 | }
132 | if (subscriptions.isEmpty()) {
133 | vertx.sharedData().getLocalMap("stomp.destinations").remove(this);
134 | }
135 | return r;
136 | }
137 |
138 | /**
139 | * Removes all subscriptions of the given connection
140 | *
141 | * @param connection the connection
142 | * @return the current instance of {@link Destination}
143 | */
144 | @Override
145 | public synchronized Destination unsubscribeConnection(StompServerConnection connection) {
146 | new ArrayList<>(subscriptions)
147 | .stream()
148 | .filter(subscription -> subscription.connection.equals(connection))
149 | .forEach(subscriptions::remove);
150 |
151 | if (subscriptions.isEmpty()) {
152 | vertx.sharedData().getLocalMap("stomp.destinations").remove(this);
153 | }
154 | return this;
155 | }
156 |
157 | /**
158 | * Handles a {@code ACK} frame.
159 | *
160 | * @param connection the connection
161 | * @param frame the {@code ACK} frame
162 | * @return {@code true} if the destination has handled the frame (meaning it has sent the message with id)
163 | */
164 | @Override
165 | public synchronized boolean ack(StompServerConnection connection, Frame frame) {
166 | return false;
167 | }
168 |
169 | /**
170 | * Handles a {@code NACK} frame.
171 | *
172 | * @param connection the connection
173 | * @param frame the {@code NACK} frame
174 | * @return {@code true} if the destination has handled the frame (meaning it has sent the message with id)
175 | */
176 | @Override
177 | public synchronized boolean nack(StompServerConnection connection, Frame frame) {
178 | return false;
179 | }
180 |
181 | /**
182 | * Gets all subscription ids for the given destination hold by the given client
183 | *
184 | * @param connection the connection (client)
185 | * @return the list of subscription id, empty if none
186 | */
187 | @Override
188 | public synchronized List getSubscriptions(StompServerConnection connection) {
189 | return subscriptions.stream()
190 | .filter(subscription -> subscription.connection.equals(connection))
191 | .map(s -> s.id)
192 | .collect(Collectors.toList());
193 | }
194 |
195 | /**
196 | * Gets the number of subscriptions attached to the current {@link Destination}.
197 | *
198 | * @return the number of subscriptions.
199 | */
200 | @Override
201 | public synchronized int numberOfSubscriptions() {
202 | return subscriptions.size();
203 | }
204 |
205 | /**
206 | * Checks whether or not the given address matches with the current destination.
207 | *
208 | * @param address the address
209 | * @return {@code true} if it matches, {@code false} otherwise.
210 | */
211 | @Override
212 | public boolean matches(String address) {
213 | return this.destination.equals(address);
214 | }
215 |
216 | private class Subscription {
217 | private final StompServerConnection connection;
218 | private final String id;
219 | private final String ackMode;
220 |
221 | private Subscription(StompServerConnection connection, Frame frame) {
222 | this.connection = connection;
223 | this.ackMode = frame.getAck() != null ? frame.getAck() : "auto";
224 | this.id = frame.getId();
225 | }
226 | }
227 |
228 | }
229 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/impl/ServerFrameImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp.impl;
18 |
19 | import io.vertx.ext.stomp.Frame;
20 | import io.vertx.ext.stomp.ServerFrame;
21 | import io.vertx.ext.stomp.StompServerConnection;
22 |
23 | import java.util.Objects;
24 |
25 | /**
26 | * A basic implementation of {@link ServerFrame}.
27 | *
28 | * @author Clement Escoffier
29 | */
30 | public class ServerFrameImpl implements ServerFrame {
31 | private final StompServerConnection connection;
32 | private final Frame frame;
33 |
34 | public ServerFrameImpl(Frame frame, StompServerConnection connection) {
35 | Objects.requireNonNull(connection);
36 | Objects.requireNonNull(frame);
37 | this.connection = connection;
38 | this.frame = frame;
39 | }
40 |
41 |
42 | /**
43 | * @return the received frame
44 | */
45 | @Override
46 | public Frame frame() {
47 | return frame;
48 | }
49 |
50 | /**
51 | * @return the connection
52 | */
53 | @Override
54 | public StompServerConnection connection() {
55 | return connection;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/impl/StompServerTCPConnectionImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp.impl;
18 |
19 | import javax.net.ssl.SSLSession;
20 |
21 | import io.vertx.core.Handler;
22 | import io.vertx.core.buffer.Buffer;
23 | import io.vertx.core.internal.logging.Logger;
24 | import io.vertx.core.internal.logging.LoggerFactory;
25 | import io.vertx.core.net.NetSocket;
26 | import io.vertx.ext.stomp.*;
27 |
28 | import java.util.Objects;
29 | import java.util.UUID;
30 | import java.util.concurrent.TimeUnit;
31 | import java.util.concurrent.atomic.AtomicBoolean;
32 |
33 | /**
34 | * Default implementation of the {@link StompServerConnection}.
35 | *
36 | * @author Clement Escoffier
37 | */
38 | public class StompServerTCPConnectionImpl implements StompServerConnection {
39 |
40 | private static final Logger log = LoggerFactory.getLogger(StompServerTCPConnectionImpl.class);
41 |
42 | private final StompServer server;
43 | private final NetSocket socket;
44 | private final String sessionId;
45 | protected final Handler handler;
46 |
47 | public volatile long lastClientActivity;
48 | private long pinger = -1;
49 | private long ponger = -1;
50 |
51 | private final AtomicBoolean closed = new AtomicBoolean(false);
52 |
53 | public StompServerTCPConnectionImpl(NetSocket socket, StompServer server, Handler writingFrameHandler) {
54 | Objects.requireNonNull(socket);
55 | Objects.requireNonNull(server);
56 | this.socket = socket;
57 | this.server = server;
58 | this.sessionId = UUID.randomUUID().toString();
59 | this.handler = writingFrameHandler;
60 | }
61 |
62 | public StompServerTCPConnectionImpl(StompServer server, Handler writingFrameHandler) {
63 | Objects.requireNonNull(server);
64 | this.socket = null;
65 | this.server = server;
66 | this.handler = writingFrameHandler;
67 | this.sessionId = UUID.randomUUID().toString();
68 | }
69 |
70 | @Override
71 | public StompServerConnection write(Frame frame) {
72 | if (handler != null) {
73 | handler.handle(new ServerFrameImpl(frame, this));
74 | }
75 | return write(frame.toBuffer(server.options().isTrailingLine()));
76 | }
77 |
78 | @Override
79 | public StompServerConnection write(Buffer buffer) {
80 | socket.write(buffer);
81 | return this;
82 | }
83 |
84 | @Override
85 | public StompServer server() {
86 | return server;
87 | }
88 |
89 | @Override
90 | public StompServerHandler handler() {
91 | return server.stompHandler();
92 | }
93 |
94 | @Override
95 | public String session() {
96 | return sessionId;
97 | }
98 |
99 | @Override
100 | public SSLSession sslSession() {
101 | return this.socket.sslSession();
102 | }
103 |
104 | @Override
105 | public void close() {
106 | if (closed.compareAndSet(false, true)) {
107 | cancelHeartbeat();
108 | handler().onClose(this);
109 | socket.close();
110 | }
111 | }
112 |
113 | /**
114 | * Sends a `PING` frame to the client. A `PING` frame is a frame containing only {@code EOL}.
115 | */
116 | @Override
117 | public void ping() {
118 | if (handler != null) {
119 | handler.handle(new ServerFrameImpl(Frames.PING, this));
120 | }
121 | socket.write(Buffer.buffer(FrameParser.EOL));
122 | }
123 |
124 | public synchronized void cancelHeartbeat() {
125 | if (pinger >= 0) {
126 | server.vertx().cancelTimer(pinger);
127 | pinger = -1;
128 | }
129 |
130 | if (ponger >= 0) {
131 | server.vertx().cancelTimer(ponger);
132 | ponger = -1;
133 | }
134 | }
135 |
136 | @Override
137 | public void onServerActivity() {
138 | lastClientActivity = System.nanoTime();
139 | }
140 |
141 | @Override
142 | public synchronized void configureHeartbeat(long ping, long pong, Handler pingHandler) {
143 | if (ping > 0) {
144 | pinger = server.vertx().setPeriodic(ping, l -> pingHandler.handle(this));
145 | }
146 | if (pong > 0) {
147 | ponger = server.vertx().setPeriodic(pong, l -> {
148 | long delta = System.nanoTime() - lastClientActivity;
149 | final long deltaInMs = TimeUnit.MILLISECONDS.convert(delta, TimeUnit.NANOSECONDS);
150 | if (deltaInMs > pong * 2) {
151 | log.warn("Disconnecting client " + this + " - no client activity in the last " + deltaInMs + " ms");
152 | close();
153 | }
154 | });
155 | }
156 | }
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/impl/StompServerWebSocketConnectionImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp.impl;
18 |
19 | import javax.net.ssl.SSLSession;
20 |
21 | import io.vertx.core.Handler;
22 | import io.vertx.core.buffer.Buffer;
23 | import io.vertx.core.http.ServerWebSocket;
24 | import io.vertx.ext.stomp.*;
25 |
26 | import java.util.Objects;
27 | import java.util.concurrent.atomic.AtomicBoolean;
28 |
29 | /**
30 | * Default implementation of the {@link StompServerConnection}.
31 | *
32 | * @author Clement Escoffier
33 | */
34 | public class StompServerWebSocketConnectionImpl extends StompServerTCPConnectionImpl implements StompServerConnection {
35 |
36 | private final ServerWebSocket socket;
37 |
38 | private final AtomicBoolean closed = new AtomicBoolean(false);
39 |
40 | public StompServerWebSocketConnectionImpl(ServerWebSocket socket, StompServer server, Handler writtenFrameHandler) {
41 | super(server, writtenFrameHandler);
42 | Objects.requireNonNull(socket);
43 | this.socket = socket;
44 | }
45 |
46 | @Override
47 | public SSLSession sslSession() {
48 | return this.socket.sslSession();
49 | }
50 |
51 | @Override
52 | public StompServerConnection write(Buffer buffer) {
53 | socket.writeBinaryMessage(buffer);
54 | return this;
55 | }
56 |
57 | @Override
58 | public void ping() {
59 | if (handler != null) {
60 | handler.handle(new ServerFrameImpl(Frames.PING, this));
61 | }
62 | socket.write(Buffer.buffer(FrameParser.EOL));
63 | }
64 |
65 | @Override
66 | public void close() {
67 | if (closed.compareAndSet(false, true)) {
68 | cancelHeartbeat();
69 | handler().onClose(this);
70 | socket.close();
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/impl/Topic.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp.impl;
18 |
19 | import io.vertx.core.Vertx;
20 | import io.vertx.ext.stomp.Command;
21 | import io.vertx.ext.stomp.Destination;
22 | import io.vertx.ext.stomp.Frame;
23 | import io.vertx.ext.stomp.StompServerConnection;
24 | import io.vertx.ext.stomp.utils.Headers;
25 |
26 | import java.util.ArrayList;
27 | import java.util.List;
28 | import java.util.UUID;
29 | import java.util.stream.Collectors;
30 |
31 | /**
32 | * Implementation of {@link io.vertx.ext.stomp.Destination} dispatching messages to all subscribers.
33 | *
34 | * @author Clement Escoffier
35 | */
36 | public class Topic implements Destination {
37 |
38 | protected final String destination;
39 |
40 | protected final List subscriptions = new ArrayList<>();
41 | protected final Vertx vertx;
42 |
43 | public Topic(Vertx vertx, String destination) {
44 | this.destination = destination;
45 | this.vertx = vertx;
46 | }
47 |
48 | /**
49 | * @return the destination address.
50 | */
51 | @Override
52 | public String destination() {
53 | return destination;
54 | }
55 |
56 | /**
57 | * Dispatches the given frame.
58 | *
59 | * @param connection the connection
60 | * @param frame the frame ({@code SEND} frame).
61 | * @return the current instance of {@link Destination}
62 | */
63 | @Override
64 | public synchronized Destination dispatch(StompServerConnection connection, Frame frame) {
65 | for (Subscription subscription : subscriptions) {
66 | String messageId = UUID.randomUUID().toString();
67 | Frame message = transform(frame, subscription, messageId);
68 | subscription.connection.write(message);
69 | }
70 | return this;
71 | }
72 |
73 | public static Frame transform(Frame frame, Subscription subscription, String messageId) {
74 | final Headers headers = Headers.create(frame.getHeaders())
75 | // Destination already set in the input headers.
76 | .add(Frame.SUBSCRIPTION, subscription.id)
77 | .add(Frame.MESSAGE_ID, messageId);
78 | if (!subscription.ackMode.equals("auto")) {
79 | // We reuse the message Id as ack Id
80 | headers.add(Frame.ACK, messageId);
81 | }
82 | return new Frame(Command.MESSAGE,
83 | headers,
84 | frame.getBody());
85 | }
86 |
87 | /**
88 | * Handles a subscription request to the current {@link Destination}. All check about the frame format and unicity
89 | * of the id should have been done beforehand.
90 | *
91 | * @param connection the connection
92 | * @param frame the {@code SUBSCRIBE} frame
93 | * @return the current instance of {@link Destination}
94 | */
95 | @Override
96 | public synchronized Destination subscribe(StompServerConnection connection, Frame frame) {
97 | Subscription subscription = new Subscription(connection, frame);
98 | subscriptions.add(subscription);
99 | return this;
100 | }
101 |
102 | /**
103 | * Handles a un-subscription request to the current {@link Destination}.
104 | *
105 | * @param connection the connection
106 | * @param frame the {@code UNSUBSCRIBE} frame
107 | * @return {@code true} if the un-subscription has been handled, {@code false} otherwise.
108 | */
109 | @Override
110 | public synchronized boolean unsubscribe(StompServerConnection connection, Frame frame) {
111 | boolean r = false;
112 | for (Subscription subscription : subscriptions) {
113 | if (subscription.connection.equals(connection) && subscription.id.equals(frame.getId())) {
114 | r = subscriptions.remove(subscription);
115 | // Subscription id are unique for a connection.
116 | break;
117 | }
118 | }
119 | if (subscriptions.isEmpty()) {
120 | vertx.sharedData().getLocalMap("stomp.destinations").remove(this);
121 | }
122 | return r;
123 | }
124 |
125 | /**
126 | * Removes all subscriptions of the given connection
127 | *
128 | * @param connection the connection
129 | * @return the current instance of {@link Destination}
130 | */
131 | @Override
132 | public synchronized Destination unsubscribeConnection(StompServerConnection connection) {
133 | new ArrayList<>(subscriptions)
134 | .stream()
135 | .filter(subscription -> subscription.connection.equals(connection))
136 | .forEach(subscriptions::remove);
137 |
138 | if (subscriptions.isEmpty()) {
139 | vertx.sharedData().getLocalMap("stomp.destinations").remove(this);
140 | }
141 | return this;
142 | }
143 |
144 | /**
145 | * Handles a {@code ACK} frame.
146 | *
147 | * @param connection the connection
148 | * @param frame the {@code ACK} frame
149 | * @return {@code true} if the destination has handled the frame (meaning it has sent the message with id)
150 | */
151 | @Override
152 | public synchronized boolean ack(StompServerConnection connection, Frame frame) {
153 | return false;
154 | }
155 |
156 | /**
157 | * Handles a {@code NACK} frame.
158 | *
159 | * @param connection the connection
160 | * @param frame the {@code NACK} frame
161 | * @return {@code true} if the destination has handled the frame (meaning it has sent the message with id)
162 | */
163 | @Override
164 | public synchronized boolean nack(StompServerConnection connection, Frame frame) {
165 | return false;
166 | }
167 |
168 | /**
169 | * Gets all subscription ids for the given destination hold by the given client
170 | *
171 | * @param connection the connection (client)
172 | * @return the list of subscription id, empty if none
173 | */
174 | @Override
175 | public synchronized List getSubscriptions(StompServerConnection connection) {
176 | return subscriptions.stream()
177 | .filter(subscription -> subscription.connection.equals(connection))
178 | .map(s -> s.id)
179 | .collect(Collectors.toList());
180 | }
181 |
182 | /**
183 | * Gets the number of subscriptions attached to the current {@link Destination}.
184 | *
185 | * @return the number of subscriptions.
186 | */
187 | @Override
188 | public synchronized int numberOfSubscriptions() {
189 | return subscriptions.size();
190 | }
191 |
192 | /**
193 | * Checks whether or not the given address matches with the current destination.
194 | *
195 | * @param address the address
196 | * @return {@code true} if it matches, {@code false} otherwise.
197 | */
198 | @Override
199 | public boolean matches(String address) {
200 | return this.destination.equals(address);
201 | }
202 |
203 | protected static class Subscription {
204 | final StompServerConnection connection;
205 | final String id;
206 | final String ackMode;
207 | final String destination;
208 |
209 | protected Subscription(StompServerConnection connection, Frame frame) {
210 | this.connection = connection;
211 | this.ackMode = frame.getAck() != null ? frame.getAck() : "auto";
212 | this.id = frame.getId();
213 | this.destination = frame.getDestination();
214 | }
215 | }
216 |
217 | }
218 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/impl/Transaction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp.impl;
18 |
19 | import io.vertx.ext.stomp.Frame;
20 | import io.vertx.ext.stomp.StompServerConnection;
21 |
22 | import java.util.ArrayList;
23 | import java.util.List;
24 |
25 | /**
26 | * Represents a STOMP transaction.
27 | * This class is thread safe.
28 | *
29 | * @author Clement Escoffier
30 | */
31 | public class Transaction {
32 | private final List frames;
33 | private final String id;
34 | private final StompServerConnection connection;
35 |
36 | public Transaction(StompServerConnection connection, String id) {
37 | this.connection = connection;
38 | this.id = id;
39 | this.frames = new ArrayList<>();
40 | }
41 |
42 | /**
43 | * @return the connection
44 | */
45 | public StompServerConnection connection() {
46 | return connection;
47 | }
48 |
49 | /**
50 | * @return the transaction id
51 | */
52 | public String id() {
53 | return id;
54 | }
55 |
56 | /**
57 | * Adds a frame to the transaction. As stated in the STOMP specification, only {@code SEND, ACK and NACK} frames
58 | * can be in transactions.
59 | *
60 | * @param frame the frame to add
61 | * @return {@code true} if the frame was added to the transaction, {@code false otherwise}. Main failure reason is the number of
62 | * frames stored in the transaction that have exceed the number of allowed frames in transaction.
63 | */
64 | public synchronized boolean addFrameToTransaction(Frame frame) {
65 | return frames.size() < connection.server().options().getMaxFrameInTransaction() && frames.add(frame);
66 | }
67 |
68 | /**
69 | * Clears the list of frames added to the transaction.
70 | *
71 | * @return the current {@link Transaction}
72 | */
73 | public synchronized Transaction clear() {
74 | frames.clear();
75 | return this;
76 | }
77 |
78 | /**
79 | * @return the ordered list of frames added to the transaction. To avoid concurrency issue, a copy is returned.
80 | */
81 | public synchronized List getFrames() {
82 | return new ArrayList<>(frames);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/impl/Transactions.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp.impl;
18 |
19 | import io.vertx.ext.stomp.StompServerConnection;
20 |
21 | import java.util.ArrayList;
22 | import java.util.List;
23 |
24 | /**
25 | * Stores the active transactions of the STOMP server.
26 | * Transactions are not shared between server instances, as transactions are 'attached' to a STOMP client (i.e.
27 | * connection). So 2 connections cannot use the same transaction object.
28 | *
29 | * @author Clement Escoffier
30 | */
31 | public class Transactions {
32 |
33 | private final static Transactions INSTANCE = new Transactions();
34 |
35 | private final List transactions = new ArrayList<>();
36 |
37 | public static Transactions instance() {
38 | return INSTANCE;
39 | }
40 |
41 | private Transactions() {
42 | // Avoid direct instantiation.
43 | }
44 |
45 | /**
46 | * Gets an active transaction.
47 | *
48 | * @param connection the connection
49 | * @param txId the transaction id
50 | * @return the transaction object, {@code null} if not found
51 | */
52 | public synchronized Transaction getTransaction(StompServerConnection connection, String txId) {
53 | return transactions.stream()
54 | .filter(t -> t.connection().equals(connection) && t.id().equals(txId))
55 | .findFirst().orElse(null);
56 | }
57 |
58 | /**
59 | * Registers a transaction.
60 | *
61 | * @param connection the connection
62 | * @param txId the transaction id
63 | * @return {@code true} if the registration succeed, {@code false} otherwise. The main reason of failure is the
64 | * non-uniqueness of the transaction id for a given client / connection
65 | */
66 | public synchronized boolean registerTransaction(StompServerConnection connection, String txId) {
67 | if (getTransaction(connection, txId) != null) {
68 | return false;
69 | }
70 | transactions.add(new Transaction(connection, txId));
71 | return true;
72 | }
73 |
74 | /**
75 | * Unregisters a transaction
76 | *
77 | * @param connection the connection used by the transaction
78 | * @param id the id of the transaction
79 | * @return {@code true} if the transaction is unregistered correctly, {@code false} otherwise.
80 | */
81 | public synchronized boolean unregisterTransaction(StompServerConnection connection, String id) {
82 | Transaction transaction = getTransaction(connection, id);
83 | return transaction != null && transactions.remove(transaction);
84 | }
85 |
86 | /**
87 | * Unregisters all transactions from the given connection / client.
88 | *
89 | * @param connection the connection
90 | */
91 | public synchronized void unregisterTransactionsFromConnection(StompServerConnection connection) {
92 | transactions.stream()
93 | .filter(transaction -> transaction.connection().equals(connection))
94 | .sorted() // Avoid using baking up collection.
95 | .forEach(transactions::remove);
96 | }
97 |
98 | /**
99 | * Gets the number of transaction handled by the server.
100 | *
101 | * @return the number of transaction, {@code 0} if none.
102 | */
103 | public synchronized int getTransactionCount() {
104 | return transactions.size();
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | @ModuleGen(name = "vertx-stomp", groupPackage = "io.vertx")
18 | package io.vertx.ext.stomp;
19 |
20 | import io.vertx.codegen.annotations.ModuleGen;
21 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/utils/Headers.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp.utils;
18 |
19 | import java.util.Arrays;
20 | import java.util.HashMap;
21 | import java.util.Map;
22 |
23 | /**
24 | * An implementation of {@link HashMap} to store STOMP frame headers. This implementations offer fluent methods to
25 | * ease the construction of the headers.
26 | *
27 | * @author Clement Escoffier
28 | */
29 | public class Headers extends HashMap {
30 |
31 | public static Headers create() {
32 | return new Headers();
33 | }
34 |
35 | public static Headers create(String... kv) {
36 | Headers headers = create();
37 | if (kv.length % 2 != 0) {
38 | throw new IllegalArgumentException("Wrong number of parameters: " + Arrays.toString(kv));
39 | }
40 | for (int i = 0; i < kv.length; i = i + 2) {
41 | headers.add(kv[i], kv[i + 1]);
42 | }
43 | return headers;
44 | }
45 |
46 | public Headers add(String header, String value) {
47 | this.put(header, value);
48 | return this;
49 | }
50 |
51 | public Headers addAll(Map other) {
52 | this.putAll(other);
53 | return this;
54 | }
55 |
56 | public static Headers create(Map headers) {
57 | return create().addAll(headers);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/io/vertx/ext/stomp/utils/Server.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.ext.stomp.utils;
18 |
19 | import java.io.IOException;
20 | import java.io.InputStream;
21 | import java.util.Scanner;
22 |
23 | /**
24 | * Class responsible for the computation of the server id. From the STOMP specification, this id must be constructed as
25 | * follows: name/version comments.
26 | *
27 | * @author Clement Escoffier
28 | */
29 | public class Server {
30 |
31 | public static final String SERVER_NAME;
32 |
33 | static {
34 | try (InputStream is = Server.class.getClassLoader().getResourceAsStream("vertx-stomp-version.txt")) {
35 | if (is == null) {
36 | throw new IllegalStateException("Cannot find vertx-stomp-version.txt on classpath");
37 | }
38 | try (Scanner scanner = new Scanner(is, "UTF-8").useDelimiter("\\A")) {
39 | SERVER_NAME = "vertx-stomp" + (scanner.hasNext() ? "/" + scanner.next() : "");
40 | }
41 | } catch (IOException e) {
42 | throw new IllegalStateException(e.getMessage());
43 | }
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/module-info.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | module io.vertx.stomp {
4 |
5 | requires static io.vertx.core.logging;
6 | requires static io.vertx.docgen;
7 | requires static io.vertx.codegen.api;
8 | requires static io.vertx.codegen.json;
9 |
10 | requires io.vertx.auth.common;
11 | requires io.vertx.core;
12 | requires io.vertx.eventbusbridge;
13 |
14 | exports io.vertx.ext.stomp;
15 |
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/resources/vertx-stomp-version.txt:
--------------------------------------------------------------------------------
1 | ${project.version}
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/FrameTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests;
18 |
19 | import io.vertx.core.buffer.Buffer;
20 | import io.vertx.ext.stomp.Command;
21 | import io.vertx.ext.stomp.Frame;
22 | import io.vertx.ext.stomp.Frames;
23 | import io.vertx.ext.stomp.impl.FrameException;
24 | import io.vertx.ext.stomp.impl.FrameParser;
25 | import io.vertx.ext.stomp.utils.Headers;
26 | import org.junit.Test;
27 |
28 | import static org.assertj.core.api.Assertions.assertThat;
29 |
30 | /**
31 | * Check the behavior of {@link Frame}.
32 | *
33 | * @author Clement Escoffier
34 | */
35 | public class FrameTest {
36 |
37 | private Frame frame;
38 |
39 | @Test
40 | public void testThatPassCodeAreNotInToString() {
41 | Frame frame = new Frame(Command.STOMP, Headers.create("login", "vertx", "passcode", "secret"), null);
42 | assertThat(frame.toString()).doesNotContain("secret").contains("********");
43 | }
44 |
45 | @Test(expected = FrameException.class)
46 | public void testThatConnectFrameCannotHaveBody() {
47 | new Frame(Command.CONNECT, Headers.create("host", "foo"),
48 | Buffer.buffer("illegal"));
49 | }
50 |
51 | @Test
52 | public void testDefaultEncoding() {
53 | final String content = "This content contains utf-8 characters: ü ß é ø î";
54 | Frame frame = new Frame(Command.SEND, Headers.create(), Buffer.buffer(content));
55 | assertThat(frame.getBodyAsString()).isEqualTo(content);
56 | }
57 |
58 | @Test
59 | public void testEncoding() {
60 | final String content = "\u03B1";
61 | Frame frame = new Frame(Command.SEND, Headers.create("content-type",
62 | "text/plain;charset=utf-16"), Buffer.buffer(content));
63 | assertThat(frame.encoding()).isEqualTo("utf-16");
64 | frame = new Frame(Command.SEND, Headers.create("content-type",
65 | "text/plain;charset=utf-8"), Buffer.buffer(content));
66 | assertThat(frame.encoding()).isEqualTo("utf-8");
67 | }
68 |
69 | @Test
70 | public void testHeaderEncoding() {
71 | String value = "test-\r\n :\\-test";
72 | String expected = "test-" + (char) 92 + (char) 114 + (char) 92 + (char) 110 + " " + (char) 92 + (char) 99 +
73 | (char) 92 + (char) 92 + "-test";
74 |
75 | Frame frame = new Frame(Command.SEND, Headers.create("header", value), null);
76 | assertThat(frame.toBuffer().toString()).contains("header:" + expected + "\n");
77 | }
78 |
79 | @Test
80 | public void testHeaderEncodingOnConnectAndConnectedFrames() {
81 | String value = "test-\r\n :\\-test";
82 | String expected = "test-\r\n :" + (char) 92 + (char) 92 + "-test";
83 |
84 | Frame frame = new Frame(Command.CONNECT, Headers.create("header", value), null);
85 | assertThat(frame.toBuffer().toString()).contains("header:" + expected + "\n");
86 |
87 | frame = new Frame(Command.CONNECTED, Headers.create("header", value), null);
88 | assertThat(frame.toBuffer().toString()).contains("header:" + expected + "\n");
89 | }
90 |
91 | @Test
92 | public void testHeartbeatComputationWith00() {
93 | Frame.Heartbeat client = Frame.Heartbeat.parse("0,0");
94 | Frame.Heartbeat server = Frame.Heartbeat.parse("0,0");
95 | assertThat(Frame.Heartbeat.computePingPeriod(client, server)).isEqualTo(0);
96 | assertThat(Frame.Heartbeat.computePongPeriod(client, server)).isEqualTo(0);
97 | assertThat(Frame.Heartbeat.computePongPeriod(server, client)).isEqualTo(0);
98 | assertThat(Frame.Heartbeat.computePingPeriod(server, client)).isEqualTo(0);
99 | }
100 |
101 | @Test
102 | public void testHeartbeatComputationWith01() {
103 | Frame.Heartbeat client = Frame.Heartbeat.parse("0,1");
104 | Frame.Heartbeat server = Frame.Heartbeat.parse("0,1");
105 | assertThat(Frame.Heartbeat.computePingPeriod(client, server)).isEqualTo(0);
106 | assertThat(Frame.Heartbeat.computePongPeriod(client, server)).isEqualTo(0);
107 | assertThat(Frame.Heartbeat.computePingPeriod(server, client)).isEqualTo(0);
108 | assertThat(Frame.Heartbeat.computePongPeriod(server, client)).isEqualTo(0);
109 | }
110 |
111 | @Test
112 | public void testHeartbeatComputationWith10() {
113 | Frame.Heartbeat client = Frame.Heartbeat.parse("1,0");
114 | Frame.Heartbeat server = Frame.Heartbeat.parse("1,0");
115 | assertThat(Frame.Heartbeat.computePingPeriod(client, server)).isEqualTo(0);
116 | assertThat(Frame.Heartbeat.computePongPeriod(client, server)).isEqualTo(0);
117 | assertThat(Frame.Heartbeat.computePingPeriod(server, client)).isEqualTo(0);
118 | assertThat(Frame.Heartbeat.computePongPeriod(server, client)).isEqualTo(0);
119 | }
120 |
121 | @Test
122 | public void testHeartbeatComputationWith11() {
123 | Frame.Heartbeat client = Frame.Heartbeat.parse("1,1");
124 | Frame.Heartbeat server = Frame.Heartbeat.parse("1,1");
125 | assertThat(Frame.Heartbeat.computePingPeriod(client, server)).isEqualTo(1);
126 | assertThat(Frame.Heartbeat.computePongPeriod(client, server)).isEqualTo(1);
127 | assertThat(Frame.Heartbeat.computePingPeriod(server, client)).isEqualTo(1);
128 | assertThat(Frame.Heartbeat.computePongPeriod(server, client)).isEqualTo(1);
129 | }
130 |
131 | @Test
132 | public void testHeartbeatComputationNotSymmetric() {
133 | Frame.Heartbeat client = Frame.Heartbeat.parse("1,2");
134 | Frame.Heartbeat server = Frame.Heartbeat.parse("3,4");
135 | assertThat(Frame.Heartbeat.computePingPeriod(client, server)).isEqualTo(4);
136 | assertThat(Frame.Heartbeat.computePongPeriod(client, server)).isEqualTo(3);
137 | assertThat(Frame.Heartbeat.computePingPeriod(server, client)).isEqualTo(3);
138 | assertThat(Frame.Heartbeat.computePongPeriod(server, client)).isEqualTo(4);
139 | }
140 |
141 | @Test
142 | public void testWithTrailingSpaces() {
143 | frame = new Frame(Command.MESSAGE, Headers.create("foo", "bar"), Buffer.buffer("hello"));
144 | assertThat(frame.toBuffer(true).toString()).endsWith(FrameParser.NULL + "\n");
145 |
146 | frame = new Frame(Command.MESSAGE, Headers.create("foo", "bar"), null);
147 | assertThat(frame.toBuffer(true).toString()).endsWith(FrameParser.NULL + "\n");
148 |
149 | frame = new Frame(Command.MESSAGE, Headers.create(), null);
150 | assertThat(frame.toBuffer(true).toString()).endsWith(FrameParser.NULL + "\n");
151 | }
152 |
153 | @Test
154 | public void testErrorFrameContentType() {
155 | Frame errorFrame = Frames.createErrorFrame("Test Message", Headers.create("foo", "bar"), "hello");
156 | assertThat(errorFrame.getHeader(Frame.CONTENT_TYPE)).isEqualTo("text/plain");
157 | }
158 |
159 | }
160 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/HeadersTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests;
18 |
19 | import io.vertx.ext.stomp.utils.Headers;
20 | import org.junit.Test;
21 |
22 | import java.util.Map;
23 |
24 | import static org.assertj.core.api.Assertions.assertThat;
25 | import static org.assertj.core.api.Assertions.entry;
26 |
27 | /**
28 | * Checks the behavior of {@link Headers}.
29 | *
30 | * @author Clement Escoffier
31 | */
32 | public class HeadersTest {
33 |
34 | @Test
35 | public void testEmptyCreation() {
36 | assertThat(Headers.create()).isInstanceOf(Map.class);
37 | }
38 |
39 | @Test
40 | public void testCreationWithEmptyArray() {
41 | final Headers headers = Headers.create(new String[0]);
42 | assertThat(headers).isInstanceOf(Map.class).isEmpty();
43 | }
44 |
45 | @Test
46 | public void testCreationWithArgs() {
47 | Headers map = Headers.create("a", "b", "c", "d");
48 | assertThat(map).containsExactly(entry("a", "b"), entry("c", "d"));
49 | }
50 |
51 | @Test(expected = IllegalArgumentException.class)
52 | public void testCreationWithWrongNumberOfArgs() {
53 | Headers.create("a", "b", "c", "d", "illegal");
54 | }
55 |
56 |
57 | @Test
58 | public void testAdd() {
59 | Headers map = Headers.create().add("a", "b").add("c", "d");
60 | map.put("e", "f");
61 | assertThat(map).containsExactly(entry("a", "b"), entry("c", "d"), entry("e", "f"));
62 | map.add("e", "f2");
63 | assertThat(map).containsExactly(entry("a", "b"), entry("c", "d"), entry("e", "f2"));
64 | }
65 |
66 | @Test
67 | public void testAddAll() {
68 | Headers map = Headers.create().add("a", "b").add("c", "d")
69 | .addAll(Headers.create("e", "f"));
70 | assertThat(map).containsExactly(entry("a", "b"), entry("c", "d"), entry("e", "f"));
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/StompClientOptionsTest.java:
--------------------------------------------------------------------------------
1 | package io.vertx.stomp.tests;
2 |
3 | import io.vertx.core.json.JsonObject;
4 | import io.vertx.ext.stomp.StompClientOptions;
5 | import org.junit.Test;
6 |
7 | import static io.vertx.ext.stomp.StompOptions.DEFAULT_STOMP_PORT;
8 | import static io.vertx.ext.stomp.StompOptions.DEFAULT_SUPPORTED_VERSIONS;
9 | import static junit.framework.TestCase.assertEquals;
10 | import static junit.framework.TestCase.assertTrue;
11 | import static org.junit.Assert.assertFalse;
12 |
13 | /**
14 | * Check the behavior of {@link StompClientOptions}.
15 | *
16 | */
17 | public class StompClientOptionsTest {
18 |
19 | @Test
20 | public void testDefaultConstructor(){
21 | StompClientOptions options = new StompClientOptions();
22 | assertFalse(options.isReuseAddress());
23 | assertEquals(options.getAcceptedVersions().indexOf(DEFAULT_SUPPORTED_VERSIONS.get(0)),
24 | (options.getAcceptedVersions().size()-1));
25 | assertEquals( DEFAULT_STOMP_PORT, options.getPort() );
26 | }
27 |
28 | @Test
29 | public void testReusedAddressInConstructFromJsonObject(){
30 | String jsonWithoutReuseAddress = "{\"host\": \"127.0.0.1\"}";
31 | StompClientOptions options0 = new StompClientOptions(new JsonObject(jsonWithoutReuseAddress));
32 | assertFalse(options0.isReuseAddress());
33 |
34 | String jsonWithValidReuseAddress = "{\"reuseAddress\": true}";
35 | StompClientOptions options1 = new StompClientOptions(new JsonObject(jsonWithValidReuseAddress));
36 | assertTrue(options1.isReuseAddress());
37 |
38 | String jsonWithInvalidReuseAddress = "{\"reuseAddress\": \"none\"}";
39 | StompClientOptions options2 = new StompClientOptions(new JsonObject(jsonWithInvalidReuseAddress));
40 | assertFalse(options2.isReuseAddress() );
41 | }
42 |
43 | @Test
44 | public void testAcceptedVersionsInConstructFromJsonObject(){
45 | String jsonWithoutAcceptedVersions = "{\"host\": \"127.0.0.1\"}";
46 | StompClientOptions options0 = new StompClientOptions(new JsonObject(jsonWithoutAcceptedVersions));
47 | assertEquals(options0.getAcceptedVersions().
48 | indexOf(DEFAULT_SUPPORTED_VERSIONS.get(0)), (options0.getAcceptedVersions().size()-1));
49 |
50 | String jsonWithValidReuseAddress = "{\"acceptedVersions\": [\"1.2\"]}";
51 | StompClientOptions options1 = new StompClientOptions(new JsonObject(jsonWithValidReuseAddress));
52 | assertEquals( 1,options1.getAcceptedVersions().size());
53 | assertTrue(options1.getAcceptedVersions().contains("1.2"));
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/StompServerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests;
18 |
19 | import io.vertx.ext.stomp.utils.Server;
20 | import org.junit.Test;
21 |
22 | import static org.assertj.core.api.Assertions.assertThat;
23 |
24 | /**
25 | * @author Clement Escoffier
26 | */
27 | public class StompServerTest {
28 |
29 | @Test
30 | public void checkThatVersionIsReadFromFile() {
31 | String server = Server.SERVER_NAME;
32 | assertThat(server).startsWith("vertx-stomp");
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/impl/AsyncLock.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.impl;
18 |
19 | import io.vertx.core.AsyncResult;
20 | import io.vertx.core.Handler;
21 |
22 | import java.util.concurrent.CountDownLatch;
23 | import java.util.concurrent.TimeUnit;
24 | import java.util.concurrent.atomic.AtomicReference;
25 |
26 | /**
27 | * An utility class to wait for success.
28 | *
29 | * @author Clement Escoffier
30 | */
31 | public class AsyncLock {
32 |
33 | private final CountDownLatch latch;
34 | private final AtomicReference> reference = new AtomicReference<>();
35 |
36 | public AsyncLock() {
37 | latch = new CountDownLatch(1);
38 | }
39 |
40 | public Handler> handler() {
41 | return (ar) -> {
42 | reference.set(ar);
43 | latch.countDown();
44 | };
45 | }
46 |
47 | public void waitForSuccess() {
48 | try {
49 | latch.await(10, TimeUnit.SECONDS);
50 | } catch (InterruptedException e) {
51 | // interrupted
52 | Thread.currentThread().interrupt();
53 | }
54 |
55 | final AsyncResult result = reference.get();
56 | if (result == null) {
57 | throw new AssertionError("Result not received after timeout");
58 | }
59 |
60 | if (result.failed()) {
61 | result.cause().printStackTrace();
62 | throw new AssertionError("Received a failed result " + result.cause().getMessage());
63 | }
64 |
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/impl/FrameTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.impl;
18 |
19 | import io.vertx.core.buffer.Buffer;
20 | import io.vertx.ext.stomp.Command;
21 | import io.vertx.ext.stomp.Frame;
22 | import org.junit.Test;
23 |
24 | import java.util.HashMap;
25 | import java.util.Map;
26 |
27 | import static org.assertj.core.api.Assertions.assertThat;
28 |
29 | public class FrameTest {
30 |
31 | @Test
32 | public void testCopyFrame() {
33 | Command command = Command.UNKNOWN;
34 | Map headers = new HashMap() {{
35 | this.put("hdr0", "val0");
36 | this.put("hdr1", "val1");
37 | }};
38 | Buffer body = Buffer.buffer("body content");
39 | Frame other = new Frame(command, headers, body);
40 | Frame current = new Frame(other);
41 | assertThat(current.getCommand()).isEqualTo(Command.UNKNOWN);
42 | assertThat(current.getHeader("hdr0")).isEqualTo("val0");
43 | assertThat(current.getHeader("hdr1")).isEqualTo("val1");
44 | assertThat(current.getBody()).isNotSameAs(other.getBody());
45 | assertThat(current.getBodyAsString()).isEqualTo("body content");
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/impl/HeaderCodecTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.impl;
18 |
19 | import io.vertx.ext.stomp.impl.FrameException;
20 | import io.vertx.ext.stomp.impl.HeaderCodec;
21 | import org.junit.Test;
22 |
23 | import static org.assertj.core.api.Assertions.assertThat;
24 |
25 | /**
26 | * Checks the behavior of the {@link HeaderCodec}.
27 | *
28 | * @author Clement Escoffier
29 | */
30 | public class HeaderCodecTest {
31 |
32 | @Test
33 | public void testDecoding() {
34 | assertThat(HeaderCodec.decode("hello", false)).isEqualTo("hello");
35 | assertThat(HeaderCodec.decode("h\\ce", false)).isEqualTo("h:e");
36 | assertThat(HeaderCodec.decode("\\c-)", false)).isEqualTo(":-)");
37 | assertThat(HeaderCodec.decode(")-\\c", false)).isEqualTo(")-:");
38 | assertThat(HeaderCodec.decode("multi\nline", false)).isEqualTo("multi\nline");
39 | assertThat(HeaderCodec.decode("multi\r\nline", false)).isEqualTo("multi\r\nline");
40 |
41 | assertThat(HeaderCodec.decode("multi" + (char) 92 + (char) 110 + "line", false))
42 | .isEqualTo("multi\nline");
43 |
44 | assertThat(HeaderCodec.decode("multi"
45 | + (char) 92 + (char) 114
46 | + (char) 92 + (char) 110 + "line", false)).isEqualTo("multi\r\nline");
47 |
48 | assertThat(HeaderCodec.decode("test"
49 | + (char) 92 + (char) 92
50 | + "slash", false)).isEqualTo("test\\slash");
51 | }
52 |
53 | @Test
54 | public void testDecodingOnConnectOrConnectedFrames() {
55 | assertThat(HeaderCodec.decode("hello", true)).isEqualTo("hello");
56 | assertThat(HeaderCodec.decode("h\\ce", true)).isEqualTo("h\\ce");
57 | assertThat(HeaderCodec.decode("\\c-)", true)).isEqualTo("\\c-)");
58 | assertThat(HeaderCodec.decode(")-\\c", true)).isEqualTo(")-\\c");
59 | assertThat(HeaderCodec.decode("multi\nline", true)).isEqualTo("multi\nline");
60 | assertThat(HeaderCodec.decode("multi\r\nline", true)).isEqualTo("multi\r\nline");
61 |
62 | assertThat(HeaderCodec.decode("multi" + (char) 92 + (char) 110 + "line", true))
63 | .isEqualTo("multi" + (char) 92 + (char) 110 + "line");
64 |
65 | assertThat(HeaderCodec.decode("multi"
66 | + (char) 92 + (char) 114
67 | + (char) 92 + (char) 110 + "line", true)).isEqualTo("multi"
68 | + (char) 92 + (char) 114
69 | + (char) 92 + (char) 110 + "line");
70 |
71 | // Slash is decoded.
72 | assertThat(HeaderCodec.decode("test"
73 | + (char) 92 + (char) 92
74 | + "slash", true)).isEqualTo("test\\slash");
75 | }
76 |
77 | @Test(expected = FrameException.class)
78 | public void testDecodingIllegalEscape() {
79 | HeaderCodec.decode("this is an illegal " + (char) 92 + (char) 116 + " escape", false);
80 | }
81 |
82 | @Test
83 | public void testEncoding() {
84 | assertThat(HeaderCodec.encode("hello", false)).isEqualTo("hello");
85 | assertThat(HeaderCodec.encode("h:e", false)).isEqualTo("h\\ce");
86 | assertThat(HeaderCodec.encode(":-)", false)).isEqualTo("\\c-)");
87 | assertThat(HeaderCodec.encode(")-:", false)).isEqualTo(")-\\c");
88 | assertThat(HeaderCodec.encode("multi\nline", false)).isEqualTo("multi" + (char) 92 + (char) 110 + "line");
89 | assertThat(HeaderCodec.encode("multi\r\nline", false)).isEqualTo("multi" + (char) 92 + (char) 114
90 | + (char) 92 + (char) 110
91 | + "line");
92 | assertThat(HeaderCodec.encode("test\\slash", false)).isEqualTo("test" + (char) 92 + (char) 92
93 | + "slash");
94 | }
95 |
96 | @Test
97 | public void testEncodingOnConnectOrConnectedFrames() {
98 | assertThat(HeaderCodec.encode("hello", true)).isEqualTo("hello");
99 | assertThat(HeaderCodec.encode("h:e", true)).isEqualTo("h:e");
100 | assertThat(HeaderCodec.encode(":-)", true)).isEqualTo(":-)");
101 | assertThat(HeaderCodec.encode(")-:", true)).isEqualTo(")-:");
102 | assertThat(HeaderCodec.encode("multi\nline", true)).isEqualTo("multi\nline");
103 | assertThat(HeaderCodec.encode("multi\r\nline", true)).isEqualTo("multi\r\nline");
104 | // Slash is encoded.
105 | assertThat(HeaderCodec.encode("test\\slash", true)).isEqualTo("test" + (char) 92 + (char) 92
106 | + "slash");
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/impl/Helper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.impl;
18 |
19 | import io.vertx.ext.stomp.Destination;
20 |
21 | import java.util.List;
22 |
23 | /**
24 | * Some helper methods.
25 | *
26 | * @author Clement Escoffier
27 | */
28 | public class Helper {
29 | public static boolean hasDestination(List destinations, String dest) {
30 | for (Destination d : destinations) {
31 | if (d.matches(dest)) {
32 | return true;
33 | }
34 | }
35 | return false;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/impl/LoadTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.impl;
18 |
19 | import com.jayway.awaitility.Awaitility;
20 | import io.vertx.core.AsyncResult;
21 | import io.vertx.core.Handler;
22 | import io.vertx.core.Vertx;
23 | import io.vertx.core.buffer.Buffer;
24 | import io.vertx.core.json.JsonObject;
25 | import io.vertx.ext.stomp.*;
26 | import io.vertx.ext.unit.TestContext;
27 | import io.vertx.ext.unit.junit.VertxUnitRunner;
28 | import org.junit.After;
29 | import org.junit.Before;
30 | import org.junit.Ignore;
31 | import org.junit.Test;
32 | import org.junit.runner.RunWith;
33 |
34 | import java.util.ArrayList;
35 | import java.util.List;
36 | import java.util.concurrent.TimeUnit;
37 | import java.util.concurrent.atomic.AtomicInteger;
38 |
39 | /**
40 | * A couple of load tests that needs to be launched manually.
41 | *
42 | * @author Clement Escoffier
43 | */
44 | @RunWith(VertxUnitRunner.class)
45 | @Ignore("Manual launch only")
46 | public class LoadTest {
47 |
48 | private Vertx vertx;
49 | private StompServer server;
50 |
51 | private List clients = new ArrayList<>();
52 | private List acked = new ArrayList<>();
53 | private List nacked = new ArrayList<>();
54 |
55 |
56 | @Before
57 | public void setUp(TestContext context) {
58 | vertx = Vertx.vertx();
59 | server = StompServer.create(vertx, new StompServerOptions().setHeartbeat(
60 | new JsonObject().put("x", 0).put("y", 0)))
61 | .handler(StompServerHandler.create(vertx)
62 | .onAckHandler(acknowledgement -> acked.addAll(acknowledgement.frames()))
63 | .onNackHandler(acknowledgement -> nacked.addAll(acknowledgement.frames())));
64 | server.listen().onComplete(context.asyncAssertSuccess());
65 | }
66 |
67 | @After
68 | public void tearDown(TestContext context) {
69 | System.out.println("Closing clients");
70 | clients.forEach(StompClient::close);
71 | System.out.println("Closing server");
72 | server.close().onComplete(context.asyncAssertSuccess());
73 | vertx.close().onComplete(context.asyncAssertSuccess());
74 | }
75 |
76 | private void client(Handler> handler) {
77 | StompClient client = StompClient.create(vertx);
78 | clients.add(client);
79 | client.connect().onComplete(handler);
80 | }
81 |
82 | @Test
83 | public void testWithMultiplePublisherAndConsumerOnOneDestination() {
84 | int publisher = 100;
85 | int consumer = 100;
86 | String dest = "/queue";
87 | int numberOfMessagePerPublisher = 100;
88 |
89 | AtomicInteger received = new AtomicInteger();
90 | AtomicInteger started = new AtomicInteger();
91 |
92 | // Init consumers
93 | for (int i = 0; i < consumer; i++) {
94 |
95 | client((ar -> {
96 | if (ar.failed()) {
97 | System.err.println("Consumer connection error " + ar.cause().getMessage());
98 | ar.cause().printStackTrace();
99 | return;
100 | }
101 | ar.result()
102 | .errorHandler(frame -> System.err.println("Consumer Error : " + frame))
103 | .subscribe(dest, frame -> {
104 | received.incrementAndGet();
105 | }).onComplete(frame -> started.incrementAndGet()
106 | );
107 | }));
108 | }
109 |
110 | Awaitility.waitAtMost(1, TimeUnit.MINUTES).until(() -> started.get() == consumer);
111 |
112 | long begin = System.currentTimeMillis();
113 | // Init producers
114 | AtomicInteger global = new AtomicInteger();
115 | for (int i = 0; i < publisher; i++) {
116 | String p = Integer.toString(i);
117 | client((ar -> {
118 | final StompClientConnection connection = ar.result();
119 | connection.errorHandler(frame -> System.err.println("Producer Error : " + frame));
120 | AtomicInteger count = new AtomicInteger();
121 | vertx.setPeriodic(10, id -> {
122 | connection.send(dest, Buffer.buffer("Hello"));
123 | global.incrementAndGet();
124 | if (count.incrementAndGet() == numberOfMessagePerPublisher) {
125 | vertx.cancelTimer(id);
126 | connection.disconnect();
127 | }
128 | });
129 | }));
130 | }
131 |
132 | Awaitility.await().atMost(1, TimeUnit.MINUTES).until(() -> {
133 | int size = received.get();
134 | return size == publisher * numberOfMessagePerPublisher * consumer;
135 | });
136 |
137 | long end = System.currentTimeMillis();
138 | System.out.println(received.get() + " messages delivered in " + (end - begin) + " ms");
139 | }
140 |
141 |
142 | @Test
143 | public void testWithASinglePublisherAndMultipleConsumersOnOneDestination() {
144 | int publisher = 1;
145 | int consumer = 200;
146 | String dest = "/queue";
147 | int numberOfMessagePerPublisher = 800;
148 |
149 | AtomicInteger received = new AtomicInteger();
150 | AtomicInteger started = new AtomicInteger();
151 |
152 | // Init consumers
153 | for (int i = 0; i < consumer; i++) {
154 |
155 | client((ar -> {
156 | if (ar.failed()) {
157 | System.err.println("Consumer connection error " + ar.cause().getMessage());
158 | ar.cause().printStackTrace();
159 | return;
160 | }
161 | ar.result()
162 | .errorHandler(frame -> System.err.println("Consumer Error : " + frame))
163 | .subscribe(dest, frame -> {
164 | received.incrementAndGet();
165 | }).onComplete(frame -> started.incrementAndGet()
166 | );
167 | }));
168 | }
169 | Awaitility.waitAtMost(1, TimeUnit.MINUTES).until(() -> started.get() == consumer);
170 |
171 | long begin = System.currentTimeMillis();
172 | // Init producers
173 | AtomicInteger global = new AtomicInteger();
174 | for (int i = 0; i < publisher; i++) {
175 | String p = Integer.toString(i);
176 | client((ar -> {
177 | final StompClientConnection connection = ar.result();
178 | connection.errorHandler(frame -> System.err.println("Producer Error : " + frame));
179 | AtomicInteger count = new AtomicInteger();
180 | vertx.setPeriodic(10, id -> {
181 | connection.send(dest, Buffer.buffer("Hello"));
182 | global.incrementAndGet();
183 | if (count.incrementAndGet() == numberOfMessagePerPublisher) {
184 | vertx.cancelTimer(id);
185 | }
186 | });
187 | }));
188 | }
189 |
190 | Awaitility.await().atMost(1, TimeUnit.MINUTES).until(() -> {
191 | int size = received.get();
192 | return size == publisher * numberOfMessagePerPublisher * consumer;
193 | });
194 |
195 | long end = System.currentTimeMillis();
196 | System.out.println(received.get() + " messages delivered in " + (end - begin) + " ms");
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/impl/QueueManagingAcknowledgmentsFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.impl;
18 |
19 | import io.vertx.core.Vertx;
20 | import io.vertx.ext.stomp.Destination;
21 | import io.vertx.ext.stomp.DestinationFactory;
22 |
23 | /**
24 | * An implementation of destination factory managing acknowledgements.
25 | *
26 | * @author Clement Escoffier
27 | */
28 | public class QueueManagingAcknowledgmentsFactory implements DestinationFactory {
29 |
30 |
31 | /**
32 | * Creates a destination for the given address.
33 | *
34 | * @param vertx the vert.x instance used by the STOMP server.
35 | * @param name the destination
36 | * @return the destination, {@code null} to reject the creation.
37 | * @see Destination#topic(Vertx, String)
38 | * @see Destination#queue(Vertx, String)
39 | */
40 | @Override
41 | public Destination create(Vertx vertx, String name) {
42 | return new QueueManagingAcknowledgments(vertx, name);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/impl/TestSendFailure.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.impl;
18 |
19 | import io.vertx.core.AsyncResult;
20 | import io.vertx.core.Handler;
21 | import io.vertx.core.Vertx;
22 | import io.vertx.core.buffer.Buffer;
23 | import io.vertx.ext.stomp.Frame;
24 | import io.vertx.ext.stomp.StompClient;
25 | import io.vertx.ext.stomp.StompServer;
26 | import io.vertx.ext.stomp.StompServerHandler;
27 | import io.vertx.ext.unit.TestContext;
28 | import io.vertx.ext.unit.junit.VertxUnitRunner;
29 | import org.junit.After;
30 | import org.junit.Before;
31 | import org.junit.Test;
32 | import org.junit.runner.RunWith;
33 |
34 | /**
35 | * Checks the {@code ACK} and {@code NACK} handling.
36 | *
37 | * @author Clement Escoffier
38 | */
39 | @RunWith(VertxUnitRunner.class)
40 | public class TestSendFailure {
41 |
42 | private Vertx vertx;
43 | private StompServer server;
44 | private StompClient client;
45 |
46 | @Before
47 | public void setUp(TestContext context) {
48 | vertx = Vertx.vertx();
49 | server = StompServer.create(vertx)
50 | .handler(StompServerHandler.create(vertx)
51 | .sendHandler(ignore -> {})
52 | .receivedFrameHandler(frame -> {
53 | if ("/queue".equalsIgnoreCase(frame.frame().getDestination())) {
54 | server.close();
55 | }
56 | })
57 | .destinationFactory(new QueueManagingAcknowledgmentsFactory()));
58 | server.listen().onComplete(context.asyncAssertSuccess());
59 | }
60 |
61 | @After
62 | public void tearDown(TestContext context) {
63 | if (client != null) {
64 | client.close();
65 | }
66 | server.close().onComplete(context.asyncAssertSuccess());
67 | vertx.close().onComplete(context.asyncAssertSuccess());
68 | }
69 |
70 |
71 | @Test
72 | public void testSimpleAck(TestContext ctx) {
73 | Handler> receiptHandler = ctx.asyncAssertFailure();
74 | client = StompClient.create(vertx);
75 | client.connect().onComplete(ctx.asyncAssertSuccess(conn -> {
76 | conn.send("/queue", Buffer.buffer("Hello")).onComplete(receiptHandler);
77 | }));
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/integration/AbstractClientIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.integration;
18 |
19 | import io.vertx.core.Vertx;
20 | import io.vertx.core.buffer.Buffer;
21 | import io.vertx.ext.stomp.*;
22 | import io.vertx.stomp.tests.impl.AsyncLock;
23 | import org.assertj.core.api.Assertions;
24 | import org.junit.After;
25 | import org.junit.Before;
26 | import org.junit.Test;
27 |
28 | import java.util.ArrayList;
29 | import java.util.List;
30 | import java.util.concurrent.TimeUnit;
31 | import java.util.concurrent.atomic.AtomicReference;
32 |
33 | import static com.jayway.awaitility.Awaitility.await;
34 | import static org.assertj.core.api.Assertions.assertThat;
35 | import static org.assertj.core.data.MapEntry.entry;
36 |
37 | /**
38 | * @author Clement Escoffier
39 | */
40 | public abstract class AbstractClientIT {
41 |
42 |
43 | protected Vertx vertx;
44 | protected List clients = new ArrayList<>();
45 |
46 | @Before
47 | public void setUp() {
48 | vertx = Vertx.vertx();
49 | }
50 |
51 | @After
52 | public void tearDown() {
53 | clients.forEach(StompClient::close);
54 | AsyncLock lock = new AsyncLock<>();
55 | vertx.close().onComplete(lock.handler());
56 | lock.waitForSuccess();
57 | }
58 |
59 | public abstract StompClientOptions getOptions();
60 |
61 | public abstract StompClientOptions getOptionsWithSSL();
62 |
63 | public String getDestination() {
64 | return "box";
65 | }
66 |
67 | /**
68 | * The test is the following:
69 | * 1. Create a client subscribing to the "box" destination
70 | * 2. Create another client sending messages to the "box" destination
71 | * 3. Ensure the the client 1 receives the message.
72 | */
73 | @Test
74 | public void testRegularConnection() {
75 | AtomicReference receiver = new AtomicReference<>();
76 | AtomicReference sender = new AtomicReference<>();
77 |
78 | AtomicReference frame = new AtomicReference<>();
79 |
80 | // Step 1.
81 | StompClient client1 = StompClient.create(vertx, getOptions());
82 | client1.connect().onComplete(connection -> {
83 | if (connection.failed()) {
84 | connection.cause().printStackTrace();
85 | } else {
86 | receiver.set(connection.result());
87 | connection.result().subscribe(getDestination(), frame::set);
88 | }
89 | });
90 | clients.add(client1);
91 |
92 | await().atMost(10, TimeUnit.SECONDS).until(() -> receiver.get() != null);
93 |
94 | // Step 2.
95 | StompClient client2 = StompClient.create(vertx, getOptions());
96 | client2.connect().onComplete(connection -> {
97 | if (connection.failed()) {
98 | connection.cause().printStackTrace();
99 | } else {
100 | sender.set(connection.result());
101 | connection.result().send(getDestination(), Buffer.buffer("hello from vert.x"));
102 | }
103 | });
104 | clients.add(client2);
105 | await().atMost(10, TimeUnit.SECONDS).until(() -> sender.get() != null);
106 |
107 | // Step 3.
108 | await().atMost(10, TimeUnit.SECONDS).until(() -> frame.get() != null);
109 | assertThat(frame.get().getCommand()).isEqualTo(Command.MESSAGE);
110 | assertThat(frame.get().getHeaders())
111 | .contains(entry("content-length", "17"))
112 | .containsKeys("destination", "message-id", "subscription");
113 | Assertions.assertThat(frame.get().getBodyAsString()).isEqualToIgnoringCase("hello from vert.x");
114 | }
115 |
116 | /**
117 | * Same test as the previous one, but using SSL.
118 | */
119 | @Test
120 | public void testSSLConnection() {
121 | if (getOptionsWithSSL() == null) {
122 | // SSL test disabled.
123 | return;
124 | }
125 | AtomicReference receiver = new AtomicReference<>();
126 | AtomicReference sender = new AtomicReference<>();
127 |
128 | AtomicReference frame = new AtomicReference<>();
129 |
130 | // Step 1.
131 | StompClient client1 = StompClient.create(vertx, getOptionsWithSSL());
132 | client1.connect().onComplete(connection -> {
133 | if (connection.failed()) {
134 | connection.cause().printStackTrace();
135 | } else {
136 | receiver.set(connection.result());
137 | connection.result().subscribe(getDestination(), frame::set);
138 | }
139 | });
140 | clients.add(client1);
141 |
142 | await().atMost(10, TimeUnit.SECONDS).until(() -> receiver.get() != null);
143 |
144 | // Step 2.
145 | StompClient client2 = StompClient.create(vertx, getOptionsWithSSL());
146 | client2.connect().onComplete(connection -> {
147 | if (connection.failed()) {
148 | connection.cause().printStackTrace();
149 | } else {
150 | sender.set(connection.result());
151 | connection.result().send(getDestination(), Buffer.buffer("hello from vert.x"));
152 | }
153 | });
154 | clients.add(client2);
155 | await().atMost(10, TimeUnit.SECONDS).until(() -> sender.get() != null);
156 |
157 | // Step 3.
158 | await().atMost(10, TimeUnit.SECONDS).until(() -> frame.get() != null);
159 | assertThat(frame.get().getCommand()).isEqualTo(Command.MESSAGE);
160 | assertThat(frame.get().getHeaders())
161 | .contains(entry("content-length", "17"))
162 | .containsKeys("destination", "message-id", "subscription");
163 | assertThat(frame.get().getBodyAsString()).isEqualToIgnoringCase("hello from vert.x");
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/integration/ActivemqDockerIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.integration;
18 |
19 | import io.vertx.ext.stomp.StompClientOptions;
20 | import org.junit.ClassRule;
21 | import org.testcontainers.containers.GenericContainer;
22 |
23 | /**
24 | * Checks that our clients can connect and interact with ActiveMQ.
25 | *
26 | * @author Clement Escoffier
27 | */
28 | public class ActivemqDockerIT extends AbstractClientIT {
29 |
30 |
31 | @ClassRule
32 | public static final GenericContainer container
33 | = new GenericContainer("rmohr/activemq:5.15.6-alpine")
34 | .withExposedPorts(61613);
35 |
36 | @Override
37 | public StompClientOptions getOptions() {
38 | return new StompClientOptions()
39 | .setHost(container.getContainerIpAddress())
40 | .setPort(container.getMappedPort(61613));
41 | }
42 |
43 | @Override
44 | public StompClientOptions getOptionsWithSSL() {
45 | // It would require configuring the SSL on activeMQ and managing the certificates
46 | return null;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/integration/ArtemisHornetQDockerIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.integration;
18 |
19 | import io.vertx.ext.stomp.StompClientOptions;
20 | import org.junit.ClassRule;
21 | import org.testcontainers.containers.GenericContainer;
22 |
23 | /**
24 | * Checks that our clients can connect and interact with ActiveMQ. This test uses the HornetQ port (5445).
25 | *
26 | * @author Clement Escoffier
27 | */
28 | public class ArtemisHornetQDockerIT extends AbstractClientIT {
29 |
30 | @ClassRule
31 | public static final GenericContainer container
32 | = new GenericContainer("vromero/activemq-artemis:2.6.3-alpine")
33 | .withExposedPorts(61613)
34 | .withExposedPorts(5445);
35 |
36 | @Override
37 | public StompClientOptions getOptions() {
38 | return new StompClientOptions()
39 | .setHost(container.getContainerIpAddress())
40 | .setPort(container.getMappedPort(5445))
41 | .setLogin("artemis")
42 | .setPasscode("simetraehcapa");
43 | }
44 |
45 | @Override
46 | public StompClientOptions getOptionsWithSSL() {
47 | return null;
48 | }
49 |
50 | /**
51 | * Artemis queue requires the "jms.queue" prefix.
52 | *
53 | * @return the destination.
54 | */
55 | @Override
56 | public String getDestination() {
57 | return "jms.queue.box-hornetq";
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/integration/ArtemisStompDockerIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.integration;
18 |
19 | import io.vertx.ext.stomp.StompClientOptions;
20 | import org.junit.ClassRule;
21 | import org.testcontainers.containers.GenericContainer;
22 |
23 | /**
24 | * Checks that our clients can connect and interact with ActiveMQ. This test uses the STOMP port.
25 | *
26 | * @author Clement Escoffier
27 | */
28 | public class ArtemisStompDockerIT extends AbstractClientIT {
29 |
30 | @ClassRule
31 | public static final GenericContainer container
32 | = new GenericContainer("vromero/activemq-artemis:2.6.3-alpine")
33 | .withExposedPorts(61613)
34 | .withExposedPorts(61616);
35 |
36 | @Override
37 | public StompClientOptions getOptions() {
38 | return new StompClientOptions()
39 | .setHost(container.getContainerIpAddress())
40 | .setPort(container.getMappedPort(61616))
41 | .setLogin("artemis")
42 | .setPasscode("simetraehcapa");
43 | }
44 |
45 | @Override
46 | public StompClientOptions getOptionsWithSSL() {
47 | return null;
48 | }
49 |
50 | /**
51 | * Artemis queue requires the "jms.queue" prefix.
52 | *
53 | * @return the destination.
54 | */
55 | @Override
56 | public String getDestination() {
57 | return "jms.queue.box";
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/integration/RabbitMQDockerIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.integration;
18 |
19 | import io.vertx.ext.stomp.StompClientOptions;
20 | import org.junit.ClassRule;
21 | import org.testcontainers.containers.BindMode;
22 | import org.testcontainers.containers.GenericContainer;
23 |
24 | /**
25 | * Checks that our clients can connect and interact with ActiveMQ.
26 | *
27 | * @author Clement Escoffier
28 | */
29 | public class RabbitMQDockerIT extends AbstractClientIT {
30 |
31 | @ClassRule
32 | public static final GenericContainer container
33 | = new GenericContainer("rabbitmq:latest")
34 | .withClasspathResourceMapping("integration/rabbitmq/enabled_plugins",
35 | "/etc/rabbitmq/enabled_plugins", BindMode.READ_ONLY)
36 | .withExposedPorts(61613);
37 |
38 | @Override
39 | public StompClientOptions getOptions() {
40 | return new StompClientOptions()
41 | .setHost(container.getContainerIpAddress())
42 | .setPort(container.getMappedPort(61613))
43 | .setBypassHostHeader(true);
44 | }
45 |
46 | @Override
47 | public StompClientOptions getOptionsWithSSL() {
48 | return null;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/integration/StiltsClientIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | *
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.integration;
18 |
19 | import io.vertx.core.Vertx;
20 | import io.vertx.ext.stomp.StompServer;
21 | import io.vertx.ext.stomp.StompServerHandler;
22 | import io.vertx.stomp.tests.impl.AsyncLock;
23 | import org.junit.After;
24 | import org.junit.Before;
25 | import org.junit.Test;
26 | import org.projectodd.stilts.stomp.*;
27 | import org.projectodd.stilts.stomp.client.ClientSubscription;
28 | import org.projectodd.stilts.stomp.client.StompClient;
29 |
30 | import javax.net.ssl.SSLException;
31 | import java.net.URISyntaxException;
32 | import java.util.concurrent.TimeUnit;
33 | import java.util.concurrent.TimeoutException;
34 | import java.util.concurrent.atomic.AtomicReference;
35 |
36 | import static com.jayway.awaitility.Awaitility.await;
37 | import static org.assertj.core.api.Assertions.assertThat;
38 |
39 | /**
40 | * Checks that the Stilts client can connect to our STOMP server.
41 | *
42 | * @author Clement Escoffier
43 | */
44 | public class StiltsClientIT {
45 |
46 | protected Vertx vertx;
47 | protected StompServer server;
48 |
49 | @Before
50 | public void setUp() {
51 | AsyncLock lock = new AsyncLock<>();
52 | vertx = Vertx.vertx();
53 | server = StompServer.create(vertx).handler(StompServerHandler.create(vertx));
54 | server.listen().onComplete(lock.handler());
55 | lock.waitForSuccess();
56 | }
57 |
58 | @After
59 | public void tearDown() {
60 | AsyncLock lock = new AsyncLock<>();
61 | server.close().onComplete(lock.handler());
62 | lock.waitForSuccess();
63 |
64 | lock = new AsyncLock<>();
65 | vertx.close().onComplete(lock.handler());
66 | lock.waitForSuccess();
67 | }
68 |
69 | @Test
70 | public void test() throws URISyntaxException, InterruptedException, TimeoutException, StompException, SSLException {
71 | StompClient client1 = new StompClient("stomp://localhost:61613");
72 | StompClient client2 = new StompClient("stomp://localhost:61613");
73 | client1.connect();
74 | client2.connect();
75 |
76 | AtomicReference frame = new AtomicReference<>();
77 |
78 | ClientSubscription subscription1 =
79 | client1.subscribe( "box" )
80 | .withMessageHandler(frame::set)
81 | .start();
82 |
83 | Headers headers = new DefaultHeaders();
84 | headers.put("header", "value");
85 | client2.send(StompMessages.createStompMessage("box", headers, "hello !"));
86 |
87 | await().atMost(10, TimeUnit.SECONDS).until(()-> frame.get() != null);
88 |
89 | assertThat(frame.get().getDestination()).isEqualTo("box");
90 | assertThat(frame.get().getContentAsString()).isEqualTo("hello !");
91 | assertThat(frame.get().getHeaders().get("header")).isEqualTo("value");
92 | assertThat(frame.get().getHeaders().get("message-id")).isNotNull();
93 | assertThat(frame.get().getHeaders().get("subscription")).isNotNull();
94 |
95 | subscription1.unsubscribe();
96 | client1.disconnect();
97 | client2.disconnect();
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/integration/StompConsumer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.integration;
18 |
19 | import io.vertx.core.Future;
20 | import io.vertx.core.VerticleBase;
21 | import io.vertx.ext.stomp.StompClient;
22 | import io.vertx.ext.stomp.StompClientOptions;
23 |
24 | /**
25 | * A verticle subscribing to a STOMP destination.
26 | *
27 | * @author Clement Escoffier
28 | */
29 | public class StompConsumer extends VerticleBase {
30 |
31 | private StompClient client;
32 |
33 | @Override
34 | public Future> start() throws Exception {
35 | System.out.println("Starting client");
36 | client = StompClient.create(vertx, new StompClientOptions(config()));
37 | return client
38 | .connect()
39 | .compose(conn -> conn
40 | .subscribe("/queue/event", frame -> System.out.println("Frame received : " + frame.getBodyAsString())));
41 | }
42 |
43 | @Override
44 | public Future> stop() throws Exception {
45 | return client.close();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/integration/StompIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.integration;
18 |
19 | import io.vertx.core.DeploymentOptions;
20 | import io.vertx.core.Vertx;
21 | import io.vertx.core.json.JsonObject;
22 |
23 | /**
24 | * Runs one of the support STOMP Broker, from 'src/test/resources/integration', configure the test, and check
25 | * messages are published and received.
26 | *
27 | * @author Clement Escoffier
28 | */
29 | public class StompIntegrationTests {
30 |
31 | public static void main(String args[]) {
32 | String host = "192.168.59.103"; // Change to localhost on linux.
33 | int port = 61613;
34 | boolean useHostHeader = true; // Set it to false for RabbitMQ
35 |
36 | JsonObject config = new JsonObject()
37 | .put("host", host)
38 | .put("port", port)
39 | .put("bypassHostHeader", !useHostHeader);
40 |
41 | Vertx vertx = Vertx.vertx();
42 | vertx.deployVerticle(StompConsumer.class.getName(), new DeploymentOptions().setConfig(config).setInstances(2));
43 | vertx.deployVerticle(StompPublisher.class.getName(), new DeploymentOptions().setConfig(config));
44 | }
45 |
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/integration/StompPublisher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.integration;
18 |
19 | import io.vertx.core.Future;
20 | import io.vertx.core.VerticleBase;
21 | import io.vertx.core.buffer.Buffer;
22 | import io.vertx.ext.stomp.StompClient;
23 | import io.vertx.ext.stomp.StompClientOptions;
24 |
25 | /**
26 | * A verticle sending messages to a STOMP destination.
27 | *
28 | * @author Clement Escoffier
29 | */
30 | public class StompPublisher extends VerticleBase {
31 |
32 | private StompClient client;
33 |
34 | @Override
35 | public Future> start() throws Exception {
36 | System.out.println("Starting publisher");
37 | client = StompClient.create(vertx, new StompClientOptions(config()));
38 | return client
39 | .connect()
40 | .onSuccess(res -> {
41 | vertx.setPeriodic(5000, l -> res.send("/queue/event", Buffer.buffer("Hello")).onComplete(frame -> {
42 | System.out.println("Receipt received");
43 | }));
44 | });
45 | }
46 |
47 | @Override
48 | public Future> stop() throws Exception {
49 | return client.close();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/verticles/MultiInstanceSubscriptionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.verticles;
18 |
19 | import com.jayway.awaitility.Awaitility;
20 | import io.vertx.core.DeploymentOptions;
21 | import io.vertx.core.Vertx;
22 | import io.vertx.core.json.JsonObject;
23 | import io.vertx.ext.unit.TestContext;
24 | import org.junit.After;
25 | import org.junit.Before;
26 | import org.junit.Test;
27 | import org.junit.runner.RunWith;
28 |
29 | import java.util.concurrent.TimeUnit;
30 |
31 | /**
32 | * @author Clement Escoffier
33 | */
34 | @RunWith(io.vertx.ext.unit.junit.VertxUnitRunner.class)
35 | public class MultiInstanceSubscriptionTest {
36 |
37 | private Vertx vertx;
38 |
39 | @Before
40 | public void setUp() {
41 | ReceiverStompClient.FRAMES.clear();
42 | vertx = Vertx.vertx();
43 | }
44 |
45 | @After
46 | public void tearDown() {
47 | vertx.close().await();
48 | }
49 |
50 | @Test
51 | public void testThatTopicSubscriptionsAreShared() {
52 | vertx.deployVerticle(StompServerVerticle::new, new DeploymentOptions().setInstances(3)).await();
53 | // Deploy the clients.
54 | vertx.deployVerticle(ReceiverStompClient::new, new DeploymentOptions().setInstances(3)).await();
55 | vertx.deployVerticle(TxSenderStompClient::new, new DeploymentOptions().setInstances(2)).await();
56 | Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> ReceiverStompClient.FRAMES.size() == 5 * 3 * 2);
57 | }
58 |
59 | @Test
60 | public void testThatQueueSubscriptionsAreShared(TestContext context) {
61 | vertx.deployVerticle(StompServerVerticle::new, new DeploymentOptions()
62 | .setConfig(new JsonObject().put("useQueue", true))
63 | .setInstances(3)).await();
64 | // Deploy the clients.
65 | vertx.deployVerticle(ReceiverStompClient::new, new DeploymentOptions().setInstances(3)).await();
66 | vertx.deployVerticle(TxSenderStompClient::new, new DeploymentOptions().setInstances(2)).await();
67 |
68 | Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> ReceiverStompClient.FRAMES.size() == 5 * 2);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/verticles/MultiInstanceTransactionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.verticles;
18 |
19 | import com.jayway.awaitility.Awaitility;
20 | import io.vertx.core.DeploymentOptions;
21 | import io.vertx.core.Vertx;
22 | import org.junit.After;
23 | import org.junit.Before;
24 | import org.junit.Test;
25 | import org.junit.runner.RunWith;
26 |
27 | import java.util.concurrent.TimeUnit;
28 |
29 | /**
30 | * @author Clement Escoffier
31 | */
32 | @RunWith(io.vertx.ext.unit.junit.VertxUnitRunner.class)
33 | public class MultiInstanceTransactionTest {
34 |
35 | private Vertx vertx;
36 |
37 | @Before
38 | public void setUp() {
39 | ReceiverStompClient.FRAMES.clear();
40 | vertx = Vertx.vertx();
41 | }
42 |
43 | @After
44 | public void tearDown() {
45 | vertx.close().await();
46 | }
47 |
48 | @Test
49 | public void testThatTransactionAreNotShared() {
50 | vertx.deployVerticle(StompServerVerticle::new, new DeploymentOptions().setInstances(3)).await();
51 | // Deploy the clients.
52 | vertx.deployVerticle(new ReceiverStompClient()).await();
53 | vertx.deployVerticle(new TxSenderStompClient()).await();
54 | Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> ReceiverStompClient.FRAMES.size() == 5);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/verticles/ReceiverStompClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.verticles;
18 |
19 | import io.vertx.core.Future;
20 | import io.vertx.core.VerticleBase;
21 | import io.vertx.ext.stomp.Frame;
22 | import io.vertx.ext.stomp.StompClient;
23 |
24 | import java.util.List;
25 | import java.util.concurrent.CopyOnWriteArrayList;
26 |
27 | /**
28 | * A STOMP client receiving messages.
29 | *
30 | * @author Clement Escoffier
31 | */
32 | public class ReceiverStompClient extends VerticleBase {
33 |
34 | public static final List FRAMES = new CopyOnWriteArrayList<>();
35 |
36 | @Override
37 | public Future> start() throws Exception {
38 | return StompClient
39 | .create(vertx)
40 | .connect()
41 | .compose(connection -> connection
42 | .receivedFrameHandler(frame -> System.out.println("Client receiving:\n" + frame))
43 | .writingFrameHandler(frame -> System.out.println("Client sending:\n" + frame))
44 | .subscribe("/queue", FRAMES::add));
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/verticles/StompServerVerticle.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.verticles;
18 |
19 | import io.vertx.core.Future;
20 | import io.vertx.core.VerticleBase;
21 | import io.vertx.ext.stomp.Destination;
22 | import io.vertx.ext.stomp.StompServer;
23 | import io.vertx.ext.stomp.StompServerHandler;
24 |
25 | /**
26 | * A verticle starting a STOMP server.
27 | *
28 | * @author Clement Escoffier
29 | */
30 | public class StompServerVerticle extends VerticleBase {
31 |
32 |
33 | private StompServer server;
34 |
35 | @Override
36 | public Future> start() throws Exception {
37 | server = StompServer.create(vertx).handler(StompServerHandler.create(vertx)
38 | .destinationFactory((vertx, name) -> {
39 | if (config().getBoolean("useQueue", false)) {
40 | return Destination.queue(vertx, name);
41 | } else {
42 | return Destination.topic(vertx, name);
43 | }
44 | }));
45 | return server.listen();
46 | }
47 |
48 | @Override
49 | public Future> stop() throws Exception {
50 | return server.close();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/test/java/io/vertx/stomp/tests/verticles/TxSenderStompClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011-2015 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package io.vertx.stomp.tests.verticles;
18 |
19 | import io.vertx.core.Future;
20 | import io.vertx.core.VerticleBase;
21 | import io.vertx.core.buffer.Buffer;
22 | import io.vertx.ext.stomp.Frame;
23 | import io.vertx.ext.stomp.StompClient;
24 | import io.vertx.ext.stomp.utils.Headers;
25 |
26 | /**
27 | * A verticle connecting to a STOMP server and sending message in a transaction.
28 | *
29 | * @author Clement Escoffier
30 | */
31 | public class TxSenderStompClient extends VerticleBase {
32 |
33 |
34 | @Override
35 | public Future> start() throws Exception {
36 | return StompClient.create(vertx)
37 | .connect()
38 | .onSuccess(connection -> {
39 | connection.errorHandler(frame -> System.err.println("Tx Sender has received an ERROR frame : \n" + frame));
40 | connection.beginTX("my-transaction");
41 | connection.send("/queue", Headers.create(Frame.TRANSACTION, "my-transaction"), Buffer.buffer("Hello"));
42 | connection.send("/queue", Headers.create(Frame.TRANSACTION, "my-transaction"), Buffer.buffer("My"));
43 | connection.send("/queue", Headers.create(Frame.TRANSACTION, "my-transaction"), Buffer.buffer("Name"));
44 | connection.send("/queue", Headers.create(Frame.TRANSACTION, "my-transaction"), Buffer.buffer("Is"));
45 | connection.send("/queue", Headers.create(Frame.TRANSACTION, "my-transaction"), Buffer.buffer("Vert.x"));
46 | connection.commit("my-transaction");
47 | connection.disconnect();
48 | });
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/test/resources/integration/rabbitmq/enabled_plugins:
--------------------------------------------------------------------------------
1 | [rabbitmq_federation_management,rabbitmq_management,rabbitmq_stomp].
2 |
3 |
--------------------------------------------------------------------------------
/src/test/resources/test-auth.properties:
--------------------------------------------------------------------------------
1 | user.admin = admin
--------------------------------------------------------------------------------