Polish SockJS client

This commit is contained in:
Rossen Stoyanchev
2015-07-28 08:11:52 -04:00
parent 6a59d00576
commit 9f557cf930
9 changed files with 347 additions and 262 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package org.springframework.web.socket.sockjs.client;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.commons.logging.Log;
@@ -66,7 +67,7 @@ public abstract class AbstractXhrTransport implements XhrTransport {
@Override
public List<TransportType> getTransportTypes() {
return (isXhrStreamingDisabled() ?
Arrays.asList(TransportType.XHR) :
Collections.singletonList(TransportType.XHR) :
Arrays.asList(TransportType.XHR_STREAMING, TransportType.XHR));
}
@@ -111,44 +112,8 @@ public abstract class AbstractXhrTransport implements XhrTransport {
return this.requestHeaders;
}
@Override
public String executeInfoRequest(URI infoUrl) {
if (logger.isDebugEnabled()) {
logger.debug("Executing SockJS Info request, url=" + infoUrl);
}
ResponseEntity<String> response = executeInfoRequestInternal(infoUrl);
if (response.getStatusCode() != HttpStatus.OK) {
if (logger.isErrorEnabled()) {
logger.error("SockJS Info request (url=" + infoUrl + ") failed: " + response);
}
throw new HttpServerErrorException(response.getStatusCode());
}
if (logger.isTraceEnabled()) {
logger.trace("SockJS Info request (url=" + infoUrl + ") response: " + response);
}
return response.getBody();
}
protected abstract ResponseEntity<String> executeInfoRequestInternal(URI infoUrl);
@Override
public void executeSendRequest(URI url, TextMessage message) {
if (logger.isTraceEnabled()) {
logger.trace("Starting XHR send, url=" + url);
}
ResponseEntity<String> response = executeSendRequestInternal(url, this.xhrSendRequestHeaders, message);
if (response.getStatusCode() != HttpStatus.NO_CONTENT) {
if (logger.isErrorEnabled()) {
logger.error("XHR send request (url=" + url + ") failed: " + response);
}
throw new HttpServerErrorException(response.getStatusCode());
}
if (logger.isTraceEnabled()) {
logger.trace("XHR send request (url=" + url + ") response: " + response);
}
}
protected abstract ResponseEntity<String> executeSendRequestInternal(URI url, HttpHeaders headers, TextMessage message);
// Transport methods
@Override
public ListenableFuture<WebSocketSession> connect(TransportRequest request, WebSocketHandler handler) {
@@ -174,6 +139,49 @@ public abstract class AbstractXhrTransport implements XhrTransport {
URI receiveUrl, HttpHeaders handshakeHeaders, XhrClientSockJsSession session,
SettableListenableFuture<WebSocketSession> connectFuture);
// InfoReceiver methods
@Override
public String executeInfoRequest(URI infoUrl) {
if (logger.isDebugEnabled()) {
logger.debug("Executing SockJS Info request, url=" + infoUrl);
}
ResponseEntity<String> response = executeInfoRequestInternal(infoUrl);
if (response.getStatusCode() != HttpStatus.OK) {
if (logger.isErrorEnabled()) {
logger.error("SockJS Info request (url=" + infoUrl + ") failed: " + response);
}
throw new HttpServerErrorException(response.getStatusCode());
}
if (logger.isTraceEnabled()) {
logger.trace("SockJS Info request (url=" + infoUrl + ") response: " + response);
}
return response.getBody();
}
protected abstract ResponseEntity<String> executeInfoRequestInternal(URI infoUrl);
// XhrTransport methods
@Override
public void executeSendRequest(URI url, TextMessage message) {
if (logger.isTraceEnabled()) {
logger.trace("Starting XHR send, url=" + url);
}
ResponseEntity<String> response = executeSendRequestInternal(url, this.xhrSendRequestHeaders, message);
if (response.getStatusCode() != HttpStatus.NO_CONTENT) {
if (logger.isErrorEnabled()) {
logger.error("XHR send request (url=" + url + ") failed: " + response);
}
throw new HttpServerErrorException(response.getStatusCode());
}
if (logger.isTraceEnabled()) {
logger.trace("XHR send request (url=" + url + ") response: " + response);
}
}
protected abstract ResponseEntity<String> executeSendRequestInternal(URI url, HttpHeaders headers, TextMessage message);
@Override
public String toString() {

View File

@@ -1,14 +1,33 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.sockjs.client;
import java.net.URI;
/**
* A simple contract for executing the SockJS "Info" request before the SockJS
* session starts. The request is used to check server capabilities such as
* whether it permits use of the WebSocket transport.
* A component that can execute the SockJS "Info" request that needs to be
* performed before the SockJS session starts in order to check server endpoint
* capabilities such as whether the endpoint permits use of WebSocket.
*
* <p>Typically {@link XhrTransport} implementations are also implementations
* of this contract.
*
* @author Rossen Stoyanchev
* @since 4.1
* @see AbstractXhrTransport
*/
public interface InfoReceiver {

View File

@@ -44,7 +44,6 @@ import org.springframework.web.socket.sockjs.SockJsException;
import org.springframework.web.socket.sockjs.SockJsTransportFailureException;
import org.springframework.web.socket.sockjs.frame.SockJsFrame;
/**
* An XHR transport based on Jetty's {@link org.eclipse.jetty.client.HttpClient}.
*
@@ -105,6 +104,25 @@ public class JettyXhrTransport extends AbstractXhrTransport implements XhrTransp
return this.httpClient.isRunning();
}
@Override
protected void connectInternal(TransportRequest request, WebSocketHandler handler,
URI url, HttpHeaders handshakeHeaders, XhrClientSockJsSession session,
SettableListenableFuture<WebSocketSession> connectFuture) {
SockJsResponseListener listener = new SockJsResponseListener(url, getRequestHeaders(), session, connectFuture);
executeReceiveRequest(url, handshakeHeaders, listener);
}
private void executeReceiveRequest(URI url, HttpHeaders headers, SockJsResponseListener listener) {
if (logger.isTraceEnabled()) {
logger.trace("Starting XHR receive request, url=" + url);
}
Request httpRequest = this.httpClient.newRequest(url).method(HttpMethod.POST);
addHttpHeaders(httpRequest, headers);
httpRequest.send(listener);
}
@Override
protected ResponseEntity<String> executeInfoRequestInternal(URI infoUrl) {
return executeRequest(infoUrl, HttpMethod.GET, getRequestHeaders(), null);
@@ -157,28 +175,11 @@ public class JettyXhrTransport extends AbstractXhrTransport implements XhrTransp
return responseHeaders;
}
@Override
protected void connectInternal(TransportRequest request, WebSocketHandler handler,
URI url, HttpHeaders handshakeHeaders, XhrClientSockJsSession session,
SettableListenableFuture<WebSocketSession> connectFuture) {
SockJsResponseListener listener = new SockJsResponseListener(url, getRequestHeaders(), session, connectFuture);
executeReceiveRequest(url, handshakeHeaders, listener);
}
private void executeReceiveRequest(URI url, HttpHeaders headers, SockJsResponseListener listener) {
if (logger.isTraceEnabled()) {
logger.trace("Starting XHR receive request, url=" + url);
}
Request httpRequest = this.httpClient.newRequest(url).method(HttpMethod.POST);
addHttpHeaders(httpRequest, headers);
httpRequest.send(listener);
}
/**
* Splits the body of an HTTP response into SockJS frames and delegates those
* to an {@link XhrClientSockJsSession}.
* Jetty client {@link org.eclipse.jetty.client.api.Response.Listener Response
* Listener} that splits the body of the response into SockJS frames and
* delegates them to the {@link XhrClientSockJsSession}.
*/
private class SockJsResponseListener extends Response.Listener.Adapter {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -93,18 +93,6 @@ public class RestTemplateXhrTransport extends AbstractXhrTransport implements Xh
}
@Override
public ResponseEntity<String> executeInfoRequestInternal(URI infoUrl) {
RequestCallback requestCallback = new XhrRequestCallback(getRequestHeaders());
return this.restTemplate.execute(infoUrl, HttpMethod.GET, requestCallback, textExtractor);
}
@Override
public ResponseEntity<String> executeSendRequestInternal(URI url, HttpHeaders headers, TextMessage message) {
RequestCallback requestCallback = new XhrRequestCallback(headers, message.getPayload());
return this.restTemplate.execute(url, HttpMethod.POST, requestCallback, textExtractor);
}
@Override
protected void connectInternal(final TransportRequest request, final WebSocketHandler handler,
final URI receiveUrl, final HttpHeaders handshakeHeaders, final XhrClientSockJsSession session,
@@ -143,11 +131,23 @@ public class RestTemplateXhrTransport extends AbstractXhrTransport implements Xh
});
}
@Override
public ResponseEntity<String> executeInfoRequestInternal(URI infoUrl) {
RequestCallback requestCallback = new XhrRequestCallback(getRequestHeaders());
return this.restTemplate.execute(infoUrl, HttpMethod.GET, requestCallback, textResponseExtractor);
}
@Override
public ResponseEntity<String> executeSendRequestInternal(URI url, HttpHeaders headers, TextMessage message) {
RequestCallback requestCallback = new XhrRequestCallback(headers, message.getPayload());
return this.restTemplate.execute(url, HttpMethod.POST, requestCallback, textResponseExtractor);
}
/**
* A simple ResponseExtractor that reads the body into a String.
*/
private final static ResponseExtractor<ResponseEntity<String>> textExtractor =
private final static ResponseExtractor<ResponseEntity<String>> textResponseExtractor =
new ResponseExtractor<ResponseEntity<String>>() {
@Override
public ResponseEntity<String> extractData(ClientHttpResponse response) throws IOException {
@@ -161,7 +161,6 @@ public class RestTemplateXhrTransport extends AbstractXhrTransport implements Xh
}
};
/**
* A RequestCallback to add the headers and (optionally) String content.
*/
@@ -191,7 +190,6 @@ public class RestTemplateXhrTransport extends AbstractXhrTransport implements Xh
}
}
/**
* Splits the body of an HTTP response into SockJS frames and delegates those
* to an {@link XhrClientSockJsSession}.

View File

@@ -25,8 +25,9 @@ import org.springframework.web.socket.sockjs.transport.TransportType;
import org.springframework.web.util.UriComponentsBuilder;
/**
* Given the base URL to a SockJS server endpoint, also provides methods to
* generate and obtain session and a server id used for construct a transport URL.
* Container for the base URL of a SockJS endpoint with additional helper methods
* to derive related SockJS URLs as the {@link #getInfoUrl() info} URL and
* {@link #getTransportUrl(TransportType) transport} URLs.
*
* @author Rossen Stoyanchev
* @since 4.1

View File

@@ -1,15 +1,36 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.sockjs.client;
import java.net.URI;
import java.security.Principal;
import org.springframework.http.HttpHeaders;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketHttpHeaders;
import org.springframework.web.socket.sockjs.frame.SockJsMessageCodec;
/**
* Represents a request to connect to a SockJS service using a specific
* Transport. A single SockJS request however may require falling back
* and therefore multiple TransportRequest instances.
* Exposes information, typically to {@link Transport} and
* {@link AbstractClientSockJsSession session} implementations, about a request
* to connect to a SockJS server endpoint over a given transport.
*
* <p>Note that a single request to connect via {@link SockJsClient} may result
* in multiple instances of {@link TransportRequest}, one for each transport
* before a connection is successfully established.
*
* @author Rossen Stoyanchev
* @since 4.1

View File

@@ -20,7 +20,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
@@ -82,6 +81,7 @@ import org.springframework.web.socket.sockjs.frame.SockJsFrame;
* </pre>
*
* @author Brian Clozel
* @author Rossen Stoyanchev
* @since 4.1.2
* @see org.xnio.Options
*/
@@ -90,10 +90,10 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
private static final AttachmentKey<String> RESPONSE_BODY = AttachmentKey.create(String.class);
private final UndertowClient httpClient;
private final OptionMap optionMap;
private final UndertowClient httpClient;
private final XnioWorker worker;
private final Pool<ByteBuffer> bufferPool;
@@ -112,29 +112,6 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
}
private static HttpHeaders toHttpHeaders(HeaderMap headerMap) {
HttpHeaders responseHeaders = new HttpHeaders();
Iterator<HttpString> names = headerMap.getHeaderNames().iterator();
while (names.hasNext()) {
HttpString name = names.next();
Iterator<String> values = headerMap.get(name).iterator();
while (values.hasNext()) {
responseHeaders.add(name.toString(), values.next());
}
}
return responseHeaders;
}
private static void addHttpHeaders(ClientRequest request, HttpHeaders headers) {
HeaderMap headerMap = request.getRequestHeaders();
for (String name : headers.keySet()) {
for (String value : headers.get(name)) {
headerMap.add(HttpString.tryFromString(name), value);
}
}
}
/**
* Return Undertow's native HTTP client
*/
@@ -152,6 +129,130 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
}
@Override
protected void connectInternal(TransportRequest request, WebSocketHandler handler, URI receiveUrl,
HttpHeaders handshakeHeaders, XhrClientSockJsSession session,
SettableListenableFuture<WebSocketSession> connectFuture) {
executeReceiveRequest(receiveUrl, handshakeHeaders, session, connectFuture);
}
private void executeReceiveRequest(final URI url, final HttpHeaders headers,
final XhrClientSockJsSession session,
final SettableListenableFuture<WebSocketSession> connectFuture) {
if (logger.isTraceEnabled()) {
logger.trace("Starting XHR receive request, url=" + url);
}
this.httpClient.connect(
new ClientCallback<ClientConnection>() {
@Override
public void completed(ClientConnection connection) {
ClientRequest request = new ClientRequest().setMethod(Methods.POST).setPath(url.getPath());
HttpString headerName = HttpString.tryFromString(HttpHeaders.HOST);
request.getRequestHeaders().add(headerName, url.getHost());
addHttpHeaders(request, headers);
connection.sendRequest(request, createReceiveCallback(url,
getRequestHeaders(), session, connectFuture));
}
@Override
public void failed(IOException ex) {
throw new SockJsTransportFailureException("Failed to execute request to " + url, ex);
}
},
url, this.worker, this.bufferPool, this.optionMap);
}
private static void addHttpHeaders(ClientRequest request, HttpHeaders headers) {
HeaderMap headerMap = request.getRequestHeaders();
for (String name : headers.keySet()) {
for (String value : headers.get(name)) {
headerMap.add(HttpString.tryFromString(name), value);
}
}
}
private ClientCallback<ClientExchange> createReceiveCallback(final URI url, final HttpHeaders headers,
final XhrClientSockJsSession sockJsSession,
final SettableListenableFuture<WebSocketSession> connectFuture) {
return new ClientCallback<ClientExchange>() {
@Override
public void completed(final ClientExchange exchange) {
exchange.setResponseListener(new ClientCallback<ClientExchange>() {
@Override
public void completed(ClientExchange result) {
ClientResponse response = result.getResponse();
if (response.getResponseCode() != 200) {
HttpStatus status = HttpStatus.valueOf(response.getResponseCode());
IoUtils.safeClose(result.getConnection());
onFailure(new HttpServerErrorException(status, "Unexpected XHR receive status"));
}
else {
SockJsResponseListener listener = new SockJsResponseListener(result.getConnection(),
url, headers, sockJsSession, connectFuture);
listener.setup(result.getResponseChannel());
}
if (logger.isTraceEnabled()) {
logger.trace("XHR receive headers: " + toHttpHeaders(response.getResponseHeaders()));
}
try {
StreamSinkChannel channel = result.getRequestChannel();
channel.shutdownWrites();
if (!channel.flush()) {
channel.getWriteSetter().set(ChannelListeners.<StreamSinkChannel>flushingChannelListener(null, null));
channel.resumeWrites();
}
}
catch (IOException exc) {
IoUtils.safeClose(result.getConnection());
onFailure(exc);
}
}
@Override
public void failed(IOException exc) {
IoUtils.safeClose(exchange.getConnection());
onFailure(exc);
}
});
}
@Override
public void failed(IOException exc) {
onFailure(exc);
}
private void onFailure(Throwable failure) {
if (connectFuture.setException(failure)) {
return;
}
if (sockJsSession.isDisconnected()) {
sockJsSession.afterTransportClosed(null);
}
else {
sockJsSession.handleTransportError(failure);
sockJsSession.afterTransportClosed(new CloseStatus(1006, failure.getMessage()));
}
}
};
}
private static HttpHeaders toHttpHeaders(HeaderMap headerMap) {
HttpHeaders httpHeaders = new HttpHeaders();
for (HttpString name : headerMap.getHeaderNames()) {
for (String value : headerMap.get(name)) {
httpHeaders.add(name.toString(), value);
}
}
return httpHeaders;
}
@Override
protected ResponseEntity<String> executeInfoRequestInternal(URI infoUrl) {
return executeRequest(infoUrl, Methods.GET, getRequestHeaders(), null);
@@ -167,13 +268,14 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
List<ClientResponse> responses = new CopyOnWriteArrayList<ClientResponse>();
try {
ClientConnection connection = this.httpClient.connect(
url, this.worker, this.bufferPool, this.optionMap).get();
ClientConnection connection = this.httpClient.connect(url, this.worker,
this.bufferPool, this.optionMap).get();
try {
ClientRequest request = new ClientRequest().setMethod(method).setPath(url.getPath());
request.getRequestHeaders().add(HttpString.tryFromString(HttpHeaders.HOST), url.getHost());
if (body != null && !body.isEmpty()) {
request.getRequestHeaders().add(HttpString.tryFromString(HttpHeaders.CONTENT_LENGTH), body.length());
HttpString headerName = HttpString.tryFromString(HttpHeaders.CONTENT_LENGTH);
request.getRequestHeaders().add(headerName, body.length());
}
addHttpHeaders(request, headers);
connection.sendRequest(request, createRequestCallback(body, responses, latch));
@@ -197,13 +299,13 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
catch (InterruptedException ex) {
throw new SockJsTransportFailureException("Interrupted while processing request to " + url, ex);
}
}
private ClientCallback<ClientExchange> createRequestCallback(final String body,
final List<ClientResponse> responses, final CountDownLatch latch) {
return new ClientCallback<ClientExchange>() {
@Override
public void completed(ClientExchange result) {
result.setResponseListener(new ClientCallback<ClientExchange>() {
@@ -242,10 +344,12 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
onFailure(latch, ex);
}
}
@Override
public void failed(IOException ex) {
onFailure(latch, ex);
}
private void onFailure(CountDownLatch latch, IOException ex) {
latch.countDown();
throw new SockJsTransportFailureException("Failed to execute request", ex);
@@ -253,103 +357,8 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
};
}
@Override
protected void connectInternal(TransportRequest request, WebSocketHandler handler, URI receiveUrl,
HttpHeaders handshakeHeaders, XhrClientSockJsSession session,
SettableListenableFuture<WebSocketSession> connectFuture) {
executeReceiveRequest(receiveUrl, handshakeHeaders, session, connectFuture);
}
private void executeReceiveRequest(final URI url, final HttpHeaders headers, final XhrClientSockJsSession session,
final SettableListenableFuture<WebSocketSession> connectFuture) {
if (logger.isTraceEnabled()) {
logger.trace("Starting XHR receive request, url=" + url);
}
this.httpClient.connect(
new ClientCallback<ClientConnection>() {
@Override
public void completed(ClientConnection result) {
final ClientRequest httpRequest = new ClientRequest().setMethod(Methods.POST).setPath(url.getPath());
httpRequest.getRequestHeaders().add(HttpString.tryFromString(HttpHeaders.HOST), url.getHost());
addHttpHeaders(httpRequest, headers);
result.sendRequest(httpRequest, createConnectCallback(url, getRequestHeaders(), session, connectFuture));
}
@Override
public void failed(IOException ex) {
throw new SockJsTransportFailureException("Failed to execute request to " + url, ex);
}
},
url, this.worker, this.bufferPool, this.optionMap);
}
private ClientCallback<ClientExchange> createConnectCallback(final URI url, final HttpHeaders headers,
final XhrClientSockJsSession sockJsSession, final SettableListenableFuture<WebSocketSession> connectFuture) {
return new ClientCallback<ClientExchange>() {
@Override
public void completed(final ClientExchange result) {
result.setResponseListener(new ClientCallback<ClientExchange>() {
@Override
public void completed(ClientExchange result) {
ClientResponse response = result.getResponse();
if (response.getResponseCode() != 200) {
HttpStatus status = HttpStatus.valueOf(response.getResponseCode());
IoUtils.safeClose(result.getConnection());
onFailure(new HttpServerErrorException(status, "Unexpected XHR receive status"));
}
else {
SockJsResponseListener listener = new SockJsResponseListener(result.getConnection(),
url, headers, sockJsSession, connectFuture);
listener.setup(result.getResponseChannel());
}
if (logger.isTraceEnabled()) {
logger.trace("XHR receive headers: " + toHttpHeaders(response.getResponseHeaders()));
}
try {
result.getRequestChannel().shutdownWrites();
if (!result.getRequestChannel().flush()) {
result.getRequestChannel().getWriteSetter()
.set(ChannelListeners.<StreamSinkChannel>flushingChannelListener(null, null));
result.getRequestChannel().resumeWrites();
}
}
catch (IOException exc) {
IoUtils.safeClose(result.getConnection());
onFailure(exc);
}
}
@Override
public void failed(IOException exc) {
IoUtils.safeClose(result.getConnection());
onFailure(exc);
}
});
}
@Override
public void failed(IOException exc) {
onFailure(exc);
}
private void onFailure(Throwable failure) {
if (connectFuture.setException(failure)) {
return;
}
if (sockJsSession.isDisconnected()) {
sockJsSession.afterTransportClosed(null);
}
else {
sockJsSession.handleTransportError(failure);
sockJsSession.afterTransportClosed(new CloseStatus(1006, failure.getMessage()));
}
}
};
}
public class SockJsResponseListener implements ChannelListener<StreamSourceChannel> {
private class SockJsResponseListener implements ChannelListener<StreamSourceChannel> {
private final ClientConnection connection;
@@ -363,8 +372,9 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
public SockJsResponseListener(ClientConnection connection, URI url, HttpHeaders headers,
XhrClientSockJsSession sockJsSession, SettableListenableFuture<WebSocketSession> connectFuture) {
public SockJsResponseListener(ClientConnection connection, URI url,
HttpHeaders headers, XhrClientSockJsSession sockJsSession,
SettableListenableFuture<WebSocketSession> connectFuture) {
this.connection = connection;
this.url = url;

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.sockjs.client;
import java.net.URI;