diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsException.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsException.java
index f30786db26..5fbf3f8a01 100644
--- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsException.java
+++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 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.
@@ -30,15 +30,30 @@ public class SockJsException extends NestedRuntimeException {
private final String sessionId;
+ /**
+ * Constructor for SockJsException.
+ * @param message the exception message
+ * @param cause the root cause
+ */
public SockJsException(String message, Throwable cause) {
this(message, null, cause);
}
+ /**
+ * Constructor for SockJsException.
+ * @param message the exception message
+ * @param sessionId the SockJS session id
+ * @param cause the root cause
+ */
public SockJsException(String message, String sessionId, Throwable cause) {
super(message, cause);
this.sessionId = sessionId;
}
+
+ /**
+ * Return the SockJS session id.
+ */
public String getSockJsSessionId() {
return this.sessionId;
}
diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsTransportFailureException.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsTransportFailureException.java
index 5151e83794..5c2b33e60e 100644
--- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsTransportFailureException.java
+++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsTransportFailureException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 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.
@@ -17,9 +17,9 @@
package org.springframework.web.socket.sockjs;
/**
- * Indicates a serious failure that occurred in the SockJS implementation as opposed to in
- * user code (e.g. IOException while writing to the response). When this exception is
- * raised, the SockJS session is typically closed.
+ * Indicates a serious failure that occurred in the SockJS implementation as opposed to
+ * in user code (e.g. IOException while writing to the response). When this exception
+ * is raised, the SockJS session is typically closed.
*
* @author Rossen Stoyanchev
* @since 4.0
@@ -27,6 +27,22 @@ package org.springframework.web.socket.sockjs;
@SuppressWarnings("serial")
public class SockJsTransportFailureException extends SockJsException {
+ /**
+ * Constructor for SockJsTransportFailureException.
+ * @param message the exception message
+ * @param cause the root cause
+ * @since 4.1.7
+ */
+ public SockJsTransportFailureException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructor for SockJsTransportFailureException.
+ * @param message the exception message
+ * @param sessionId the SockJS session id
+ * @param cause the root cause
+ */
public SockJsTransportFailureException(String message, String sessionId, Throwable cause) {
super(message, sessionId, cause);
}
diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/DefaultTransportRequest.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/DefaultTransportRequest.java
index f641288fc9..bf1eacdcd7 100644
--- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/DefaultTransportRequest.java
+++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/DefaultTransportRequest.java
@@ -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.
@@ -205,7 +205,7 @@ class DefaultTransportRequest implements TransportRequest {
if (isTimeoutFailure) {
String message = "Connect timed out for " + DefaultTransportRequest.this;
logger.error(message);
- ex = new SockJsTransportFailureException(message, getSockJsUrlInfo().getSessionId(), null);
+ ex = new SockJsTransportFailureException(message, getSockJsUrlInfo().getSessionId(), ex);
}
if (fallbackRequest != null) {
logger.error(DefaultTransportRequest.this + " failed. Falling back on next transport.", ex);
diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/JettyXhrTransport.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/JettyXhrTransport.java
index dc148a106c..710400a321 100644
--- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/JettyXhrTransport.java
+++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/JettyXhrTransport.java
@@ -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.
@@ -126,7 +126,7 @@ public class JettyXhrTransport extends AbstractXhrTransport implements XhrTransp
response = httpRequest.send();
}
catch (Exception ex) {
- throw new SockJsTransportFailureException("Failed to execute request to " + url, null, ex);
+ throw new SockJsTransportFailureException("Failed to execute request to " + url, ex);
}
HttpStatus status = HttpStatus.valueOf(response.getStatus());
HttpHeaders responseHeaders = toHttpHeaders(response.getHeaders());
diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/UndertowXhrTransport.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/UndertowXhrTransport.java
index 5002d7177b..4c14937c16 100644
--- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/UndertowXhrTransport.java
+++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/UndertowXhrTransport.java
@@ -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.
@@ -65,6 +65,7 @@ import org.springframework.web.socket.sockjs.frame.SockJsFrame;
/**
* An XHR transport based on Undertow's {@link io.undertow.client.UndertowClient}.
+ * Compatible with Undertow 1.0, 1.1, 1.2.
*
*
When used for testing purposes (e.g. load testing) or for specific use cases
* (like HTTPS configuration), a custom OptionMap should be provided:
@@ -88,13 +89,15 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
private static final AttachmentKey RESPONSE_BODY = AttachmentKey.create(String.class);
- private final Pool bufferPool;
+
+ private final UndertowClient httpClient;
private final OptionMap optionMap;
private final XnioWorker worker;
- private final UndertowClient httpClient;
+ private final Pool bufferPool;
+
public UndertowXhrTransport() throws IOException {
this(OptionMap.builder().parse(Options.WORKER_NAME, "SockJSClient").getMap());
@@ -102,19 +105,20 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
public UndertowXhrTransport(OptionMap optionMap) throws IOException {
Assert.notNull(optionMap, "'optionMap' is required");
- this.bufferPool = new ByteBufferSlicePool(1048, 1048);
+ this.httpClient = UndertowClient.getInstance();
this.optionMap = optionMap;
this.worker = Xnio.getInstance().createWorker(optionMap);
- this.httpClient = UndertowClient.getInstance();
+ this.bufferPool = new ByteBufferSlicePool(1048, 1048);
}
+
private static HttpHeaders toHttpHeaders(HeaderMap headerMap) {
HttpHeaders responseHeaders = new HttpHeaders();
Iterator names = headerMap.getHeaderNames().iterator();
- while(names.hasNext()) {
+ while (names.hasNext()) {
HttpString name = names.next();
Iterator values = headerMap.get(name).iterator();
- while(values.hasNext()) {
+ while (values.hasNext()) {
responseHeaders.add(name.toString(), values.next());
}
}
@@ -130,21 +134,24 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
}
}
+
/**
* Return Undertow's native HTTP client
*/
public UndertowClient getHttpClient() {
- return httpClient;
+ return this.httpClient;
}
/**
- * Return the {@link org.xnio.XnioWorker} backing the I/O operations for Undertow's HTTP client
+ * Return the {@link org.xnio.XnioWorker} backing the I/O operations
+ * for Undertow's HTTP client.
* @see org.xnio.Xnio
*/
public XnioWorker getWorker() {
return this.worker;
}
+
@Override
protected ResponseEntity executeInfoRequestInternal(URI infoUrl) {
return executeRequest(infoUrl, Methods.GET, getRequestHeaders(), null);
@@ -156,23 +163,23 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
}
protected ResponseEntity executeRequest(URI url, HttpString method, HttpHeaders headers, String body) {
+ CountDownLatch latch = new CountDownLatch(1);
+ List responses = new CopyOnWriteArrayList();
- final CountDownLatch latch = new CountDownLatch(1);
- final List responses = new CopyOnWriteArrayList();
try {
- final 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 {
- final ClientRequest request = new ClientRequest().setMethod(method).setPath(url.getPath());
+ ClientRequest request = new ClientRequest().setMethod(method).setPath(url.getPath());
request.getRequestHeaders().add(HttpString.tryFromString(HttpHeaders.HOST), url.getHost());
- if (body !=null && !body.isEmpty()) {
+ if (body != null && !body.isEmpty()) {
request.getRequestHeaders().add(HttpString.tryFromString(HttpHeaders.CONTENT_LENGTH), body.length());
}
addHttpHeaders(request, headers);
connection.sendRequest(request, createRequestCallback(body, responses, latch));
latch.await();
- final ClientResponse response = responses.iterator().next();
+ ClientResponse response = responses.iterator().next();
HttpStatus status = HttpStatus.valueOf(response.getResponseCode());
HttpHeaders responseHeaders = toHttpHeaders(response.getResponseHeaders());
String responseBody = response.getAttachment(RESPONSE_BODY);
@@ -185,10 +192,10 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
}
}
catch (IOException ex) {
- throw new SockJsTransportFailureException("Failed to execute request to " + url, null, ex);
+ throw new SockJsTransportFailureException("Failed to execute request to " + url, ex);
}
- catch(InterruptedException ex) {
- throw new SockJsTransportFailureException("Failed to execute request to " + url, null, ex);
+ catch (InterruptedException ex) {
+ throw new SockJsTransportFailureException("Interrupted while processing request to " + url, ex);
}
}
@@ -203,21 +210,18 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
@Override
public void completed(final ClientExchange result) {
responses.add(result.getResponse());
-
new StringReadChannelListener(result.getConnection().getBufferPool()) {
@Override
protected void stringDone(String string) {
result.getResponse().putAttachment(RESPONSE_BODY, string);
latch.countDown();
}
-
@Override
protected void error(IOException ex) {
onFailure(latch, ex);
}
}.setup(result.getResponseChannel());
}
-
@Override
public void failed(IOException ex) {
onFailure(latch, ex);
@@ -238,28 +242,28 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
onFailure(latch, ex);
}
}
-
@Override
public void failed(IOException ex) {
onFailure(latch, ex);
}
-
- private void onFailure(final CountDownLatch latch, IOException ex) {
+ private void onFailure(CountDownLatch latch, IOException ex) {
latch.countDown();
- throw new SockJsTransportFailureException("Failed to execute request", null, ex);
+ throw new SockJsTransportFailureException("Failed to execute request", ex);
}
};
}
@Override
protected void connectInternal(TransportRequest request, WebSocketHandler handler, URI receiveUrl,
- HttpHeaders handshakeHeaders, XhrClientSockJsSession session, SettableListenableFuture connectFuture) {
+ HttpHeaders handshakeHeaders, XhrClientSockJsSession session,
+ SettableListenableFuture connectFuture) {
executeReceiveRequest(receiveUrl, handshakeHeaders, session, connectFuture);
}
private void executeReceiveRequest(final URI url, final HttpHeaders headers, final XhrClientSockJsSession session,
final SettableListenableFuture connectFuture) {
+
if (logger.isTraceEnabled()) {
logger.trace("Starting XHR receive request, url=" + url);
}
@@ -273,10 +277,9 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
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, null, ex);
+ throw new SockJsTransportFailureException("Failed to execute request to " + url, ex);
}
},
url, this.worker, this.bufferPool, this.optionMap);
@@ -289,11 +292,9 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
return new ClientCallback() {
@Override
public void completed(final ClientExchange result) {
-
result.setResponseListener(new ClientCallback() {
@Override
- public void completed(final ClientExchange result) {
-
+ public void completed(ClientExchange result) {
ClientResponse response = result.getResponse();
if (response.getResponseCode() != 200) {
HttpStatus status = HttpStatus.valueOf(response.getResponseCode());
@@ -320,9 +321,7 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
IoUtils.safeClose(result.getConnection());
onFailure(exc);
}
-
}
-
@Override
public void failed(IOException exc) {
IoUtils.safeClose(result.getConnection());
@@ -330,12 +329,10 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
}
});
}
-
@Override
public void failed(IOException exc) {
onFailure(exc);
}
-
private void onFailure(Throwable failure) {
if (connectFuture.setException(failure)) {
return;
@@ -349,21 +346,26 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
}
}
};
-
}
+
public class SockJsResponseListener implements ChannelListener {
private final ClientConnection connection;
+
private final URI url;
+
private final HttpHeaders headers;
+
private final XhrClientSockJsSession session;
+
private final SettableListenableFuture connectFuture;
private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
public SockJsResponseListener(ClientConnection connection, URI url, HttpHeaders headers,
XhrClientSockJsSession sockJsSession, SettableListenableFuture connectFuture) {
+
this.connection = connection;
this.url = url;
this.headers = headers;
@@ -371,7 +373,7 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
this.connectFuture = connectFuture;
}
- public void setup(final StreamSourceChannel channel) {
+ public void setup(StreamSourceChannel channel) {
channel.suspendReads();
channel.getReadSetter().set(this);
channel.resumeReads();
@@ -388,7 +390,6 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
}
Pooled pooled = this.connection.getBufferPool().allocate();
-
try {
int r;
do {
@@ -403,7 +404,7 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
onSuccess();
}
else {
- while(buffer.hasRemaining()) {
+ while (buffer.hasRemaining()) {
int b = buffer.get();
if (b == '\n') {
handleFrame();
@@ -413,8 +414,8 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra
}
}
}
-
- } while (r > 0);
+ }
+ while (r > 0);
}
catch (IOException exc) {
onFailure(exc);