diff options
author | Joffrey BION <joffrey.bion@gmail.com> | 2017-05-28 15:49:55 +0200 |
---|---|---|
committer | Joffrey BION <joffrey.bion@gmail.com> | 2017-05-28 15:49:55 +0200 |
commit | e2176e95af5cd4c76ddfd5c77fdfdca04c1ff32b (patch) | |
tree | ee86f7d5eda8efd5f5c07b7e76397a86e4926123 | |
parent | Remove ForbiddenSubscriptionException (diff) | |
download | seven-wonders-e2176e95af5cd4c76ddfd5c77fdfdca04c1ff32b.tar.gz seven-wonders-e2176e95af5cd4c76ddfd5c77fdfdca04c1ff32b.tar.bz2 seven-wonders-e2176e95af5cd4c76ddfd5c77fdfdca04c1ff32b.zip |
Extract Jackstomp as dependency
10 files changed, 8 insertions, 423 deletions
diff --git a/backend/build.gradle b/backend/build.gradle index 612c32c7..83afffbb 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -19,6 +19,7 @@ sourceCompatibility = 1.8 repositories { mavenCentral() + jcenter() } dependencies { @@ -36,6 +37,7 @@ dependencies { compile 'org.webjars:jquery:3.1.0' testCompile 'org.springframework.boot:spring-boot-starter-test' + testCompile 'org.hildan.jackstomp:jackstomp:1.0.0' } checkstyle { diff --git a/backend/src/test/java/org/luxons/sevenwonders/SevenWondersTest.java b/backend/src/test/java/org/luxons/sevenwonders/SevenWondersTest.java index fe0c4d83..16b55892 100644 --- a/backend/src/test/java/org/luxons/sevenwonders/SevenWondersTest.java +++ b/backend/src/test/java/org/luxons/sevenwonders/SevenWondersTest.java @@ -4,6 +4,8 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.hildan.jackstomp.Channel; +import org.hildan.jackstomp.JackstompSession; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -14,8 +16,6 @@ import org.luxons.sevenwonders.test.api.ApiPlayer; import org.luxons.sevenwonders.test.api.ApiPlayerTurnInfo; import org.luxons.sevenwonders.test.api.SevenWondersClient; import org.luxons.sevenwonders.test.api.SevenWondersSession; -import org.luxons.sevenwonders.test.client.Channel; -import org.luxons.sevenwonders.test.client.JackstompSession; import org.springframework.boot.context.embedded.LocalServerPort; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; diff --git a/backend/src/test/java/org/luxons/sevenwonders/test/api/SevenWondersClient.java b/backend/src/test/java/org/luxons/sevenwonders/test/api/SevenWondersClient.java index cf7f46c7..ade43677 100644 --- a/backend/src/test/java/org/luxons/sevenwonders/test/api/SevenWondersClient.java +++ b/backend/src/test/java/org/luxons/sevenwonders/test/api/SevenWondersClient.java @@ -3,8 +3,8 @@ package org.luxons.sevenwonders.test.api; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; -import org.luxons.sevenwonders.test.client.JackstompClient; -import org.luxons.sevenwonders.test.client.JackstompSession; +import org.hildan.jackstomp.JackstompClient; +import org.hildan.jackstomp.JackstompSession; public class SevenWondersClient { diff --git a/backend/src/test/java/org/luxons/sevenwonders/test/api/SevenWondersSession.java b/backend/src/test/java/org/luxons/sevenwonders/test/api/SevenWondersSession.java index 3f76a54b..b6c36f8a 100644 --- a/backend/src/test/java/org/luxons/sevenwonders/test/api/SevenWondersSession.java +++ b/backend/src/test/java/org/luxons/sevenwonders/test/api/SevenWondersSession.java @@ -1,11 +1,11 @@ package org.luxons.sevenwonders.test.api; +import org.hildan.jackstomp.Channel; +import org.hildan.jackstomp.JackstompSession; import org.luxons.sevenwonders.actions.ChooseNameAction; import org.luxons.sevenwonders.actions.CreateGameAction; import org.luxons.sevenwonders.actions.JoinGameAction; import org.luxons.sevenwonders.errors.UIError; -import org.luxons.sevenwonders.test.client.Channel; -import org.luxons.sevenwonders.test.client.JackstompSession; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; diff --git a/backend/src/test/java/org/luxons/sevenwonders/test/client/Channel.java b/backend/src/test/java/org/luxons/sevenwonders/test/client/Channel.java deleted file mode 100644 index 6d3f1f41..00000000 --- a/backend/src/test/java/org/luxons/sevenwonders/test/client/Channel.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.luxons.sevenwonders.test.client; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.TimeUnit; - -import org.springframework.messaging.simp.stomp.StompSession.Subscription; - -public class Channel<T> { - - private static final int DEFAULT_RECEPTION_TIMEOUT_IN_SECONDS = 10; - - private final BlockingQueue<T> messageQueue; - - private final Subscription subscription; - - Channel(Subscription subscription, BlockingQueue<T> messageQueue) { - this.subscription = subscription; - this.messageQueue = messageQueue; - } - - public T next() throws InterruptedException { - return messageQueue.poll(DEFAULT_RECEPTION_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); - } - - public T next(long timeout, TimeUnit unit) throws InterruptedException { - return messageQueue.poll(timeout, unit); - } - - public void unsubscribe() { - subscription.unsubscribe(); - } -} diff --git a/backend/src/test/java/org/luxons/sevenwonders/test/client/EmptyMsgStompFrameHandler.java b/backend/src/test/java/org/luxons/sevenwonders/test/client/EmptyMsgStompFrameHandler.java deleted file mode 100644 index bd04daea..00000000 --- a/backend/src/test/java/org/luxons/sevenwonders/test/client/EmptyMsgStompFrameHandler.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.luxons.sevenwonders.test.client; - -import java.lang.reflect.Type; -import java.util.concurrent.BlockingQueue; - -import org.springframework.messaging.simp.stomp.StompFrameHandler; -import org.springframework.messaging.simp.stomp.StompHeaders; - -class EmptyMsgStompFrameHandler implements StompFrameHandler { - - private final BlockingQueue<Object> blockingQueue; - - EmptyMsgStompFrameHandler(BlockingQueue<Object> blockingQueue) { - this.blockingQueue = blockingQueue; - } - - @Override - public Type getPayloadType(StompHeaders stompHeaders) { - return Object.class; - } - - @Override - public void handleFrame(StompHeaders stompHeaders, Object o) { - if (o != null) { - throw new IllegalArgumentException("Non-null payload in EmptyMsgStompFrameHandler"); - } - blockingQueue.offer(new Object()); - } -} diff --git a/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompClient.java b/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompClient.java deleted file mode 100644 index 43c8edeb..00000000 --- a/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompClient.java +++ /dev/null @@ -1,124 +0,0 @@ -package org.luxons.sevenwonders.test.client; - -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import org.springframework.context.Lifecycle; -import org.springframework.messaging.converter.MappingJackson2MessageConverter; -import org.springframework.messaging.simp.stomp.StompSession; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.web.socket.client.WebSocketClient; -import org.springframework.web.socket.client.standard.StandardWebSocketClient; -import org.springframework.web.socket.messaging.WebSocketStompClient; -import org.springframework.web.socket.sockjs.client.SockJsClient; -import org.springframework.web.socket.sockjs.client.Transport; -import org.springframework.web.socket.sockjs.client.WebSocketTransport; - -/** - * A simple wrapper around a {@link WebSocketStompClient} which preconfigures websocket transports, a Jackson - * converter for messages, and allows for the creation of {@link JackstompSession}s. - */ -public class JackstompClient implements Lifecycle { - - private static final long DEFAULT_CONNECTION_TIMEOUT_IN_SECONDS = 15; - - private final WebSocketStompClient client; - - /** - * Creates a {@code JackstompClient} with convenient defaults. It creates a pre-configured - * {@link WebSocketStompClient} using Spring {@link SockJsClient} and a Jackson message converter. - */ - public JackstompClient() { - this(createDefaultStompClient()); - } - - /** - * Creates a {@code JackstompClient} based on the given {@link WebSocketStompClient}. This allows you to - * configure as you please the actual client used by Jackstomp. - */ - public JackstompClient(WebSocketStompClient client) { - this.client = client; - } - - private static WebSocketStompClient createDefaultStompClient() { - WebSocketStompClient stompClient = new WebSocketStompClient(createWebSocketClient()); - stompClient.setMessageConverter(new MappingJackson2MessageConverter()); // for custom object exchanges - stompClient.setTaskScheduler(createTaskScheduler()); // for heartbeats - return stompClient; - } - - private static WebSocketClient createWebSocketClient() { - return new SockJsClient(createWsTransports()); - } - - private static List<Transport> createWsTransports() { - return Collections.singletonList(new WebSocketTransport(new StandardWebSocketClient())); - } - - private static ThreadPoolTaskScheduler createTaskScheduler() { - ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); - taskScheduler.afterPropertiesSet(); - return taskScheduler; - } - - /** - * Connects to the given URL. Uses a default timeout of {@value #DEFAULT_CONNECTION_TIMEOUT_IN_SECONDS} seconds. - * - * @param url - * the URL to connect to - * - * @return a new {@link JackstompSession} for the created connection - * @throws InterruptedException - * if the current thread was interrupted while waiting for the connection - * @throws ExecutionException - * if an exception was thrown while connecting - * @throws TimeoutException - * if the connection took too long to establish - */ - public JackstompSession connect(String url) throws InterruptedException, ExecutionException, TimeoutException { - return connect(url, DEFAULT_CONNECTION_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); - } - - /** - * Connects to the given URL. Uses a default timeout of {@value #DEFAULT_CONNECTION_TIMEOUT_IN_SECONDS} seconds. - * - * @param url - * the URL to connect to - * @param timeout - * the maximum time to wait for the connection - * @param unit - * the time unit of the timeout argument - * - * @return a new {@link JackstompSession} for the created connection - * @throws InterruptedException - * if the current thread was interrupted while waiting for the connection - * @throws ExecutionException - * if an exception was thrown while connecting - * @throws TimeoutException - * if the connection took too long to establish - */ - public JackstompSession connect(String url, long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - StompSession session = client.connect(url, new LoggingStompSessionHandler()).get(timeout, unit); - session.setAutoReceipt(true); - return new JackstompSession(session); - } - - @Override - public void start() { - client.start(); - } - - @Override - public void stop() { - client.stop(); - } - - @Override - public boolean isRunning() { - return client.isRunning(); - } -} diff --git a/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompSession.java b/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompSession.java deleted file mode 100644 index db361fca..00000000 --- a/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompSession.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.luxons.sevenwonders.test.client; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingDeque; - -import org.springframework.messaging.simp.stomp.StompFrameHandler; -import org.springframework.messaging.simp.stomp.StompHeaders; -import org.springframework.messaging.simp.stomp.StompSession; - -/** - * Wrapper a {@link StompSession} that provides additional subscription features. It can return a {@link Channel} - * upon subscription for a given payload type, which can then be queried actively. This is particularly useful for - * unit tests. - */ -public class JackstompSession implements StompSession { - - private final StompSession stompSession; - - /** - * Creates a new {@code JackstompSession} wrapping the given {@link StompSession}. - * - * @param stompSession - * the session to wrap - */ - public JackstompSession(StompSession stompSession) { - this.stompSession = stompSession; - } - - @Override - public Receiptable send(String destination, Object payload) { - return stompSession.send(destination, payload); - } - - @Override - public Receiptable send(StompHeaders headers, Object payload) { - return stompSession.send(headers, payload); - } - - @Override - public Subscription subscribe(String destination, StompFrameHandler handler) { - return stompSession.subscribe(destination, handler); - } - - @Override - public Subscription subscribe(StompHeaders headers, StompFrameHandler handler) { - return stompSession.subscribe(headers, handler); - } - - /** - * Subscribe to the given destination by sending a SUBSCRIBE frame and queue received messages in the returned - * {@link Channel}. - * - * @param destination - * the destination to subscribe to - * @param payloadType - * the expected type for received messages - * - * @return a new channel to use to actively check for received values, unsubscribe, or track receipts - */ - public <T> Channel<T> subscribe(String destination, Class<T> payloadType) { - BlockingQueue<T> blockingQueue = new LinkedBlockingDeque<>(); - StompFrameHandler frameHandler = new QueuedStompFrameHandler<>(blockingQueue, payloadType); - Subscription sub = stompSession.subscribe(destination, frameHandler); - return new Channel<>(sub, blockingQueue); - } - - /** - * Subscribe to the given destination by sending a SUBSCRIBE frame and queue received messages in the returned - * {@link Channel}. The messages are expected to have no body, and empty {@link Object}s are queued to be able to - * track reception events. - * - * @param destination - * the destination to subscribe to - * - * @return a new channel to use to actively check for received events, unsubscribe, or track receipts - */ - public Channel<Object> subscribeEmptyMsgs(String destination) { - BlockingQueue<Object> blockingQueue = new LinkedBlockingDeque<>(); - StompFrameHandler frameHandler = new EmptyMsgStompFrameHandler(blockingQueue); - Subscription sub = stompSession.subscribe(destination, frameHandler); - return new Channel<>(sub, blockingQueue); - } - - @Override - public Receiptable acknowledge(String messageId, boolean consumed) { - return stompSession.acknowledge(messageId, consumed); - } - - @Override - public String getSessionId() { - return stompSession.getSessionId(); - } - - @Override - public boolean isConnected() { - return stompSession.isConnected(); - } - - @Override - public void setAutoReceipt(boolean enabled) { - stompSession.setAutoReceipt(enabled); - } - - @Override - public void disconnect() { - stompSession.disconnect(); - } - - /** - * Makes a synchronous request/response call via a send and a subscription. - * - * @param payload - * the payload to send on the given requestDestination - * @param responseType - * the type of the response to expect on the responseDestination - * @param requestDestination - * the destination to send payload to - * @param responseDestination - * the destination to expect a response on - * @param <T> - * the type of object to receive as a response - * - * @return the response object, deserialized from the JSON received on the responseDestination, or null if no - * response was received before timeout. - * @throws InterruptedException - * if the current thread was interrupted while waiting for the response - */ - public <T> T request(Object payload, Class<T> responseType, String requestDestination, String responseDestination) - throws InterruptedException { - Channel<T> channel = subscribe(responseDestination, responseType); - send(requestDestination, payload); - T msg = channel.next(); - channel.unsubscribe(); - return msg; - } - - /** - * Makes a synchronous request/response call via a send and a subscription, but does not expect any value as - * response, just an event message with no body. - * - * @param payload - * the payload to send on the given requestDestination - * @param requestDestination - * the destination to send payload to - * @param responseDestination - * the destination to expect a response on - * - * @return true if the event message was received before timeout, false otherwise - * @throws InterruptedException - * if the current thread was interrupted while waiting for the response - */ - public boolean request(Object payload, String requestDestination, String responseDestination) - throws InterruptedException { - Channel<Object> channel = subscribeEmptyMsgs(responseDestination); - send(requestDestination, payload); - Object msg = channel.next(); - channel.unsubscribe(); - return msg != null; - } -} diff --git a/backend/src/test/java/org/luxons/sevenwonders/test/client/LoggingStompSessionHandler.java b/backend/src/test/java/org/luxons/sevenwonders/test/client/LoggingStompSessionHandler.java deleted file mode 100644 index abf223fd..00000000 --- a/backend/src/test/java/org/luxons/sevenwonders/test/client/LoggingStompSessionHandler.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.luxons.sevenwonders.test.client; - -import java.lang.reflect.Type; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.messaging.simp.stomp.StompCommand; -import org.springframework.messaging.simp.stomp.StompHeaders; -import org.springframework.messaging.simp.stomp.StompSession; -import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter; - -class LoggingStompSessionHandler extends StompSessionHandlerAdapter { - - private static final Logger logger = LoggerFactory.getLogger(LoggingStompSessionHandler.class); - - @Override - public void afterConnected(StompSession session, StompHeaders connectedHeaders) { - logger.info("Client connected under session id " + session.getSessionId()); - } - - @Override - public void handleFrame(StompHeaders headers, Object payload) { - } - - @Override - public Type getPayloadType(StompHeaders headers) { - return String.class; - } - - @Override - public void handleException(StompSession session, StompCommand command, StompHeaders headers, byte[] payload, - Throwable exception) { - logger.error("Exception thrown in session " + session.getSessionId(), exception); - } - - @Override - public void handleTransportError(StompSession session, Throwable exception) { - logger.error("Transport exception thrown in session " + session.getSessionId(), exception); - } -} diff --git a/backend/src/test/java/org/luxons/sevenwonders/test/client/QueuedStompFrameHandler.java b/backend/src/test/java/org/luxons/sevenwonders/test/client/QueuedStompFrameHandler.java deleted file mode 100644 index 7c682af0..00000000 --- a/backend/src/test/java/org/luxons/sevenwonders/test/client/QueuedStompFrameHandler.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.luxons.sevenwonders.test.client; - -import java.lang.reflect.Type; -import java.util.concurrent.BlockingQueue; - -import org.springframework.messaging.simp.stomp.StompFrameHandler; -import org.springframework.messaging.simp.stomp.StompHeaders; - -class QueuedStompFrameHandler<T> implements StompFrameHandler { - - private final BlockingQueue<T> blockingQueue; - - private final Class<T> type; - - QueuedStompFrameHandler(BlockingQueue<T> blockingQueue, Class<T> type) { - this.blockingQueue = blockingQueue; - this.type = type; - } - - @Override - public Type getPayloadType(StompHeaders stompHeaders) { - return type; - } - - @Override - public void handleFrame(StompHeaders stompHeaders, Object o) { - if (o == null) { - throw new IllegalArgumentException("Unsupported null payloads in this type of frame handler"); - } - blockingQueue.offer(type.cast(o)); - } -} |