protected void initSockJsClient(Transport... transports) { this.sockJsClient = new SockJsClient(Arrays.asList(transports)); this.sockJsClient.start(); }
@Override public ListenableFuture<WebSocketSession> doHandshake( WebSocketHandler handler, String uriTemplate, Object... uriVars) { Assert.notNull(uriTemplate, "uriTemplate must not be null"); URI uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVars).encode().toUri(); return doHandshake(handler, null, uri); }
@Override public final ListenableFuture<WebSocketSession> doHandshake( WebSocketHandler handler, @Nullable WebSocketHttpHeaders headers, URI url) { Assert.notNull(handler, "WebSocketHandler is required"); Assert.notNull(url, "URL is required"); String scheme = url.getScheme(); if (!supportedProtocols.contains(scheme)) { throw new IllegalArgumentException("Invalid scheme: '" + scheme + "'"); } SettableListenableFuture<WebSocketSession> connectFuture = new SettableListenableFuture<>(); try { SockJsUrlInfo sockJsUrlInfo = new SockJsUrlInfo(url); ServerInfo serverInfo = getServerInfo(sockJsUrlInfo, getHttpRequestHeaders(headers)); createRequest(sockJsUrlInfo, headers, serverInfo).connect(handler, connectFuture); } catch (Throwable exception) { if (logger.isErrorEnabled()) { logger.error("Initial SockJS \"Info\" request to server failed, url=" + url, exception); } connectFuture.setException(exception); } return connectFuture; }
private DefaultTransportRequest createRequest( SockJsUrlInfo urlInfo, @Nullable HttpHeaders headers, ServerInfo serverInfo) { List<DefaultTransportRequest> requests = new ArrayList<>(this.transports.size()); for (Transport transport : this.transports) { for (TransportType type : transport.getTransportTypes()) { if (serverInfo.isWebSocketEnabled() || !TransportType.WEBSOCKET.equals(type)) { requests.add(new DefaultTransportRequest(urlInfo, headers, getHttpRequestHeaders(headers), transport, type, getMessageCodec())); } } } if (CollectionUtils.isEmpty(requests)) { throw new IllegalStateException( "No transports: " + urlInfo + ", webSocketEnabled=" + serverInfo.isWebSocketEnabled()); } for (int i = 0; i < requests.size() - 1; i++) { DefaultTransportRequest request = requests.get(i); Principal user = getUser(); if (user != null) { request.setUser(user); } if (this.connectTimeoutScheduler != null) { request.setTimeoutValue(serverInfo.getRetransmissionTimeout()); request.setTimeoutScheduler(this.connectTimeoutScheduler); } request.setFallbackRequest(requests.get(i + 1)); } return requests.get(0); }
@Bean public WebSocketClient webSocketClient() { StandardWebSocketClient webSocketClient = new StandardWebSocketClient(); Map<String, Object> userProperties = new HashMap<>(); userProperties.put(Constants.IO_TIMEOUT_MS_PROPERTY, "" + (Constants.IO_TIMEOUT_MS_DEFAULT * 6)); webSocketClient.setUserProperties(userProperties); return new SockJsClient(Collections.singletonList(new WebSocketTransport(webSocketClient))); }
private WebSocketSession tryConnect(String serverUrl) throws ExecutionException, InterruptedException { log.debug("Connecting to " + serverUrl); StandardWebSocketClient standardWebSocketClient = new StandardWebSocketClient(); List<Transport> transports = new ArrayList<>(1); transports.add(new WebSocketTransport(standardWebSocketClient)); SockJsClient sockJsClient = new SockJsClient(transports); return sockJsClient .doHandshake(new ClientWebSocketHandler(), serverUrl + "cubaglevt-ws/handler") .get(); }
@Override public void start() { if (!isRunning()) { this.running = true; for (Transport transport : this.transports) { if (transport instanceof Lifecycle) { Lifecycle lifecycle = (Lifecycle) transport; if (!lifecycle.isRunning()) { lifecycle.start(); } } } } }
@Before @SuppressWarnings("unchecked") public void setup() { this.infoReceiver = mock(InfoReceiver.class); this.webSocketTransport = new TestTransport("WebSocketTestTransport"); this.xhrTransport = new XhrTestTransport("XhrTestTransport"); List<Transport> transports = new ArrayList<>(); transports.add(this.webSocketTransport); transports.add(this.xhrTransport); this.sockJsClient = new SockJsClient(transports); this.sockJsClient.setInfoReceiver(this.infoReceiver); this.connectCallback = mock(ListenableFutureCallback.class); }
@Test(timeout = 5000) public void fallbackAfterConnectTimeout() throws Exception { TestClientHandler clientHandler = new TestClientHandler(); this.testFilter.sleepDelayMap.put("/xhr_streaming", 10000L); this.testFilter.sendErrorMap.put("/xhr_streaming", 503); initSockJsClient(createXhrTransport()); this.sockJsClient.setConnectTimeoutScheduler(this.wac.getBean(ThreadPoolTaskScheduler.class)); WebSocketSession clientSession = sockJsClient.doHandshake(clientHandler, this.baseUrl + "/echo").get(); assertEquals("Fallback didn't occur", XhrClientSockJsSession.class, clientSession.getClass()); TextMessage message = new TextMessage("message1"); clientSession.sendMessage(message); clientHandler.awaitMessage(message, 5000); clientSession.close(); }
@Test public void connectAndUseSubsetOfHandshakeHeadersForHttpRequests() throws Exception { ArgumentCaptor<HttpHeaders> headersCaptor = setupInfoRequest(false); this.xhrTransport.setStreamingDisabled(true); WebSocketHttpHeaders headers = new WebSocketHttpHeaders(); headers.set("foo", "bar"); headers.set("auth", "123"); this.sockJsClient.setHttpHeaderNames("auth"); this.sockJsClient.doHandshake(handler, headers, new URI(URL)).addCallback(this.connectCallback); assertEquals(1, headersCaptor.getValue().size()); assertEquals("123", headersCaptor.getValue().getFirst("auth")); assertEquals(1, this.xhrTransport.getRequest().getHttpRequestHeaders().size()); assertEquals("123", this.xhrTransport.getRequest().getHttpRequestHeaders().getFirst("auth")); }
@Nullable private HttpHeaders getHttpRequestHeaders(@Nullable HttpHeaders webSocketHttpHeaders) { if (getHttpHeaderNames() == null || webSocketHttpHeaders == null) { return webSocketHttpHeaders; } else { HttpHeaders httpHeaders = new HttpHeaders(); for (String name : getHttpHeaderNames()) { List<String> values = webSocketHttpHeaders.get(name); if (values != null) { httpHeaders.put(name, values); } } return httpHeaders; } }
/** * Create a {@code SockJsClient} with the given transports. * <p>If the list includes an {@link XhrTransport} (or more specifically an * implementation of {@link InfoReceiver}) the instance is used to initialize * the {@link #setInfoReceiver(InfoReceiver) infoReceiver} property, or * otherwise is defaulted to {@link RestTemplateXhrTransport}. * @param transports the (non-empty) list of transports to use */ public SockJsClient(List<Transport> transports) { Assert.notEmpty(transports, "No transports provided"); this.transports = new ArrayList<>(transports); this.infoReceiver = initInfoReceiver(transports); if (jackson2Present) { this.messageCodec = new Jackson2SockJsMessageCodec(); } }
private DefaultTransportRequest createRequest( SockJsUrlInfo urlInfo, @Nullable HttpHeaders headers, ServerInfo serverInfo) { List<DefaultTransportRequest> requests = new ArrayList<>(this.transports.size()); for (Transport transport : this.transports) { for (TransportType type : transport.getTransportTypes()) { if (serverInfo.isWebSocketEnabled() || !TransportType.WEBSOCKET.equals(type)) { requests.add(new DefaultTransportRequest(urlInfo, headers, getHttpRequestHeaders(headers), transport, type, getMessageCodec())); } } } if (CollectionUtils.isEmpty(requests)) { throw new IllegalStateException( "No transports: " + urlInfo + ", webSocketEnabled=" + serverInfo.isWebSocketEnabled()); } for (int i = 0; i < requests.size() - 1; i++) { DefaultTransportRequest request = requests.get(i); Principal user = getUser(); if (user != null) { request.setUser(user); } if (this.connectTimeoutScheduler != null) { request.setTimeoutValue(serverInfo.getRetransmissionTimeout()); request.setTimeoutScheduler(this.connectTimeoutScheduler); } request.setFallbackRequest(requests.get(i + 1)); } return requests.get(0); }
@Bean public WebSocketClient webSocketClient() { return new SockJsClient(Collections.<Transport>singletonList(new WebSocketTransport(new StandardWebSocketClient()))); }
@Override public void stop() { if (isRunning()) { this.running = false; for (Transport transport : this.transports) { if (transport instanceof Lifecycle) { Lifecycle lifecycle = (Lifecycle) transport; if (lifecycle.isRunning()) { lifecycle.stop(); } } } } }
@Nullable private HttpHeaders getHttpRequestHeaders(@Nullable HttpHeaders webSocketHttpHeaders) { if (getHttpHeaderNames() == null || webSocketHttpHeaders == null) { return webSocketHttpHeaders; } else { HttpHeaders httpHeaders = new HttpHeaders(); for (String name : getHttpHeaderNames()) { List<String> values = webSocketHttpHeaders.get(name); if (values != null) { httpHeaders.put(name, values); } } return httpHeaders; } }
/** * Create a {@code SockJsClient} with the given transports. * <p>If the list includes an {@link XhrTransport} (or more specifically an * implementation of {@link InfoReceiver}) the instance is used to initialize * the {@link #setInfoReceiver(InfoReceiver) infoReceiver} property, or * otherwise is defaulted to {@link RestTemplateXhrTransport}. * @param transports the (non-empty) list of transports to use */ public SockJsClient(List<Transport> transports) { Assert.notEmpty(transports, "No transports provided"); this.transports = new ArrayList<>(transports); this.infoReceiver = initInfoReceiver(transports); if (jackson2Present) { this.messageCodec = new Jackson2SockJsMessageCodec(); } }
@Test public void connectSockJsInfoCached() throws Exception { setupInfoRequest(true); this.sockJsClient.doHandshake(handler, URL); this.sockJsClient.doHandshake(handler, URL); this.sockJsClient.doHandshake(handler, URL); verify(this.infoReceiver, times(1)).executeInfoRequest(any(), any()); }
@Override public final ListenableFuture<WebSocketSession> doHandshake( WebSocketHandler handler, @Nullable WebSocketHttpHeaders headers, URI url) { Assert.notNull(handler, "WebSocketHandler is required"); Assert.notNull(url, "URL is required"); String scheme = url.getScheme(); if (!supportedProtocols.contains(scheme)) { throw new IllegalArgumentException("Invalid scheme: '" + scheme + "'"); } SettableListenableFuture<WebSocketSession> connectFuture = new SettableListenableFuture<>(); try { SockJsUrlInfo sockJsUrlInfo = new SockJsUrlInfo(url); ServerInfo serverInfo = getServerInfo(sockJsUrlInfo, getHttpRequestHeaders(headers)); createRequest(sockJsUrlInfo, headers, serverInfo).connect(handler, connectFuture); } catch (Throwable exception) { if (logger.isErrorEnabled()) { logger.error("Initial SockJS \"Info\" request to server failed, url=" + url, exception); } connectFuture.setException(exception); } return connectFuture; }
private DefaultTransportRequest createRequest( SockJsUrlInfo urlInfo, @Nullable HttpHeaders headers, ServerInfo serverInfo) { List<DefaultTransportRequest> requests = new ArrayList<>(this.transports.size()); for (Transport transport : this.transports) { for (TransportType type : transport.getTransportTypes()) { if (serverInfo.isWebSocketEnabled() || !TransportType.WEBSOCKET.equals(type)) { requests.add(new DefaultTransportRequest(urlInfo, headers, getHttpRequestHeaders(headers), transport, type, getMessageCodec())); } } } if (CollectionUtils.isEmpty(requests)) { throw new IllegalStateException( "No transports: " + urlInfo + ", webSocketEnabled=" + serverInfo.isWebSocketEnabled()); } for (int i = 0; i < requests.size() - 1; i++) { DefaultTransportRequest request = requests.get(i); Principal user = getUser(); if (user != null) { request.setUser(user); } if (this.connectTimeoutScheduler != null) { request.setTimeoutValue(serverInfo.getRetransmissionTimeout()); request.setTimeoutScheduler(this.connectTimeoutScheduler); } request.setFallbackRequest(requests.get(i + 1)); } return requests.get(0); }