Add SockJsSessionFactory
This commit is contained in:
parent
3a2c15b0fd
commit
71e82069ce
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2002-2013 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.sockjs;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface SockJsSessionFactory<S extends SockJsSession>{
|
||||
|
||||
S createSession(String sessionId);
|
||||
|
||||
}
|
||||
|
|
@ -58,7 +58,7 @@ public abstract class AbstractSockJsService implements SockJsConfiguration {
|
|||
|
||||
private int streamBytesLimit = 128 * 1024;
|
||||
|
||||
private boolean jsessionIdCookieNeeded = true;
|
||||
private boolean jsessionIdCookieRequired = true;
|
||||
|
||||
private long heartbeatTime = 25 * 1000;
|
||||
|
||||
|
|
@ -138,17 +138,17 @@ public abstract class AbstractSockJsService implements SockJsConfiguration {
|
|||
* Set this option to indicate if a JSESSIONID cookie should be created. The
|
||||
* default value is "true".
|
||||
*/
|
||||
public AbstractSockJsService setJsessionIdCookieNeeded(boolean jsessionIdCookieNeeded) {
|
||||
this.jsessionIdCookieNeeded = jsessionIdCookieNeeded;
|
||||
public AbstractSockJsService setJsessionIdCookieRequired(boolean jsessionIdCookieRequired) {
|
||||
this.jsessionIdCookieRequired = jsessionIdCookieRequired;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether setting JSESSIONID cookie is necessary.
|
||||
* @see #setJsessionIdCookieNeeded(boolean)
|
||||
* @see #setJsessionIdCookieRequired(boolean)
|
||||
*/
|
||||
public boolean isJsessionIdCookieNeeded() {
|
||||
return this.jsessionIdCookieNeeded;
|
||||
public boolean isJsessionIdCookieRequired() {
|
||||
return this.jsessionIdCookieRequired;
|
||||
}
|
||||
|
||||
public AbstractSockJsService setHeartbeatTime(long heartbeatTime) {
|
||||
|
|
@ -344,7 +344,7 @@ public abstract class AbstractSockJsService implements SockJsConfiguration {
|
|||
addCorsHeaders(request, response);
|
||||
addNoCacheHeaders(response);
|
||||
|
||||
String content = String.format(INFO_CONTENT, random.nextInt(), isJsessionIdCookieNeeded(), isWebSocketsEnabled());
|
||||
String content = String.format(INFO_CONTENT, random.nextInt(), isJsessionIdCookieRequired(), isWebSocketsEnabled());
|
||||
response.getBody().write(content.getBytes());
|
||||
}
|
||||
else if (HttpMethod.OPTIONS.equals(request.getMethod())) {
|
||||
|
|
|
|||
|
|
@ -29,12 +29,6 @@ public interface TransportHandler {
|
|||
|
||||
TransportType getTransportType();
|
||||
|
||||
boolean canCreateSession();
|
||||
|
||||
SockJsSessionSupport createSession(String sessionId);
|
||||
|
||||
boolean handleNoSession(ServerHttpRequest request, ServerHttpResponse response);
|
||||
|
||||
void handleRequest(ServerHttpRequest request, ServerHttpResponse response, SockJsSessionSupport session)
|
||||
throws Exception;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
*/
|
||||
package org.springframework.sockjs.server;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
|
||||
|
|
@ -25,30 +28,34 @@ import org.springframework.http.HttpMethod;
|
|||
*/
|
||||
public enum TransportType {
|
||||
|
||||
WEBSOCKET("websocket", HttpMethod.GET, false),
|
||||
WEBSOCKET("websocket", HttpMethod.GET),
|
||||
|
||||
XHR("xhr", HttpMethod.POST, true),
|
||||
XHR_SEND("xhr_send", HttpMethod.POST, true),
|
||||
XHR("xhr", HttpMethod.POST, "cors", "jsessionid", "no_cache"),
|
||||
|
||||
JSONP("jsonp", HttpMethod.GET, false),
|
||||
JSONP_SEND("jsonp_send", HttpMethod.POST, false),
|
||||
XHR_SEND("xhr_send", HttpMethod.POST, "cors", "jsessionid", "no_cache"),
|
||||
|
||||
XHR_STREAMING("xhr_streaming", HttpMethod.POST, true),
|
||||
EVENT_SOURCE("eventsource", HttpMethod.GET, false),
|
||||
HTML_FILE("htmlfile", HttpMethod.GET, false);
|
||||
JSONP("jsonp", HttpMethod.GET, "jsessionid", "no_cache"),
|
||||
|
||||
JSONP_SEND("jsonp_send", HttpMethod.POST, "jsessionid", "no_cache"),
|
||||
|
||||
XHR_STREAMING("xhr_streaming", HttpMethod.POST, "cors", "jsessionid", "no_cache"),
|
||||
|
||||
EVENT_SOURCE("eventsource", HttpMethod.GET, "jsessionid", "no_cache"),
|
||||
|
||||
HTML_FILE("htmlfile", HttpMethod.GET, "jsessionid", "no_cache");
|
||||
|
||||
|
||||
private final String value;
|
||||
|
||||
private final HttpMethod httpMethod;
|
||||
|
||||
private final boolean corsSupported;
|
||||
private final List<String> headerHints;
|
||||
|
||||
|
||||
private TransportType(String value, HttpMethod httpMethod, boolean corsSupported) {
|
||||
private TransportType(String value, HttpMethod httpMethod, String... headerHints) {
|
||||
this.value = value;
|
||||
this.httpMethod = httpMethod;
|
||||
this.corsSupported = corsSupported;
|
||||
this.headerHints = Arrays.asList(headerHints);
|
||||
}
|
||||
|
||||
public String value() {
|
||||
|
|
@ -62,11 +69,16 @@ public enum TransportType {
|
|||
return this.httpMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are cross-domain requests (CORS) supported?
|
||||
*/
|
||||
public boolean isCorsSupported() {
|
||||
return this.corsSupported;
|
||||
public boolean setsNoCacheHeader() {
|
||||
return this.headerHints.contains("no_cache");
|
||||
}
|
||||
|
||||
public boolean supportsCors() {
|
||||
return this.headerHints.contains("cors");
|
||||
}
|
||||
|
||||
public boolean setsJsessionIdCookie() {
|
||||
return this.headerHints.contains("jsessionid");
|
||||
}
|
||||
|
||||
public static TransportType fromValue(String transportValue) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import org.springframework.http.server.ServerHttpResponse;
|
|||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.sockjs.SockJsHandler;
|
||||
import org.springframework.sockjs.SockJsSessionFactory;
|
||||
import org.springframework.sockjs.SockJsSessionSupport;
|
||||
import org.springframework.sockjs.server.AbstractSockJsService;
|
||||
import org.springframework.sockjs.server.TransportHandler;
|
||||
|
|
@ -188,14 +189,14 @@ public class DefaultSockJsService extends AbstractSockJsService
|
|||
|
||||
HttpMethod supportedMethod = transportType.getHttpMethod();
|
||||
if (!supportedMethod.equals(request.getMethod())) {
|
||||
if (HttpMethod.OPTIONS.equals(request.getMethod()) && transportType.isCorsSupported()) {
|
||||
if (HttpMethod.OPTIONS.equals(request.getMethod()) && transportType.supportsCors()) {
|
||||
response.setStatusCode(HttpStatus.NO_CONTENT);
|
||||
addCorsHeaders(request, response, supportedMethod, HttpMethod.OPTIONS);
|
||||
addCacheHeaders(response);
|
||||
}
|
||||
else {
|
||||
List<HttpMethod> supportedMethods = Arrays.asList(supportedMethod);
|
||||
if (transportType.isCorsSupported()) {
|
||||
if (transportType.supportsCors()) {
|
||||
supportedMethods.add(HttpMethod.OPTIONS);
|
||||
}
|
||||
sendMethodNotAllowed(response, supportedMethods);
|
||||
|
|
@ -204,21 +205,22 @@ public class DefaultSockJsService extends AbstractSockJsService
|
|||
}
|
||||
|
||||
SockJsSessionSupport session = getSockJsSession(sessionId, transportHandler);
|
||||
if ((session == null) && !transportHandler.handleNoSession(request, response)) {
|
||||
return;
|
||||
}
|
||||
|
||||
addNoCacheHeaders(response);
|
||||
if (session != null) {
|
||||
if (transportType.setsNoCacheHeader()) {
|
||||
addNoCacheHeaders(response);
|
||||
}
|
||||
|
||||
if (isJsessionIdCookieNeeded()) {
|
||||
Cookie cookie = request.getCookies().getCookie("JSESSIONID");
|
||||
String jsid = (cookie != null) ? cookie.getValue() : "dummy";
|
||||
// TODO: bypass use of Cookie object (causes Jetty to set Expires header)
|
||||
response.getHeaders().set("Set-Cookie", "JSESSIONID=" + jsid + ";path=/"); // TODO
|
||||
}
|
||||
if (transportType.setsJsessionIdCookie() && isJsessionIdCookieRequired()) {
|
||||
Cookie cookie = request.getCookies().getCookie("JSESSIONID");
|
||||
String jsid = (cookie != null) ? cookie.getValue() : "dummy";
|
||||
// TODO: bypass use of Cookie object (causes Jetty to set Expires header)
|
||||
response.getHeaders().set("Set-Cookie", "JSESSIONID=" + jsid + ";path=/"); // TODO
|
||||
}
|
||||
|
||||
if (transportType.isCorsSupported()) {
|
||||
addCorsHeaders(request, response);
|
||||
if (transportType.supportsCors()) {
|
||||
addCorsHeaders(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
transportHandler.handleRequest(request, response, session);
|
||||
|
|
@ -231,22 +233,22 @@ public class DefaultSockJsService extends AbstractSockJsService
|
|||
return session;
|
||||
}
|
||||
|
||||
if (!transportHandler.canCreateSession()) {
|
||||
return null;
|
||||
}
|
||||
if (transportHandler instanceof SockJsSessionFactory) {
|
||||
SockJsSessionFactory<?> sessionFactory = (SockJsSessionFactory<?>) transportHandler;
|
||||
|
||||
synchronized (this.sessions) {
|
||||
session = this.sessions.get(sessionId);
|
||||
if (session != null) {
|
||||
synchronized (this.sessions) {
|
||||
session = this.sessions.get(sessionId);
|
||||
if (session != null) {
|
||||
return session;
|
||||
}
|
||||
logger.debug("Creating new session with session id \"" + sessionId + "\"");
|
||||
session = (SockJsSessionSupport) sessionFactory.createSession(sessionId);
|
||||
this.sessions.put(sessionId, session);
|
||||
return session;
|
||||
}
|
||||
|
||||
logger.debug("Creating new session with session id \"" + sessionId + "\"");
|
||||
session = transportHandler.createSession(sessionId);
|
||||
this.sessions.put(sessionId, session);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,25 +51,20 @@ public abstract class AbstractHttpReceivingTransportHandler implements Transport
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canCreateSession() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SockJsSessionSupport createSession(String sessionId) {
|
||||
throw new IllegalStateException("Transport handlers receiving messages do not create new sessions");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleNoSession(ServerHttpRequest request, ServerHttpResponse response) {
|
||||
response.setStatusCode(HttpStatus.NOT_FOUND);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(ServerHttpRequest request, ServerHttpResponse response, SockJsSessionSupport session)
|
||||
public final void handleRequest(ServerHttpRequest request, ServerHttpResponse response, SockJsSessionSupport session)
|
||||
throws Exception {
|
||||
|
||||
if (session == null) {
|
||||
response.setStatusCode(HttpStatus.NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
handleRequestInternal(request, response, session);
|
||||
}
|
||||
|
||||
protected void handleRequestInternal(ServerHttpRequest request, ServerHttpResponse response,
|
||||
SockJsSessionSupport session) throws Exception {
|
||||
|
||||
String[] messages = null;
|
||||
try {
|
||||
messages = readMessages(request);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import org.apache.commons.logging.LogFactory;
|
|||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.sockjs.SockJsSessionFactory;
|
||||
import org.springframework.sockjs.SockJsSessionSupport;
|
||||
import org.springframework.sockjs.server.SockJsConfiguration;
|
||||
import org.springframework.sockjs.server.SockJsFrame;
|
||||
|
|
@ -34,7 +35,8 @@ import org.springframework.sockjs.server.TransportHandler;
|
|||
* @author Rossen Stoyanchev
|
||||
* @since 4.0
|
||||
*/
|
||||
public abstract class AbstractHttpSendingTransportHandler implements TransportHandler {
|
||||
public abstract class AbstractHttpSendingTransportHandler
|
||||
implements TransportHandler, SockJsSessionFactory<SockJsSessionSupport> {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
|
|
@ -49,16 +51,6 @@ public abstract class AbstractHttpSendingTransportHandler implements TransportHa
|
|||
return this.sockJsConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCreateSession() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleNoSession(ServerHttpRequest request, ServerHttpResponse response) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleRequest(ServerHttpRequest request, ServerHttpResponse response,
|
||||
SockJsSessionSupport session) throws Exception {
|
||||
|
|
|
|||
|
|
@ -50,21 +50,6 @@ public abstract class AbstractWebSocketTransportHandler implements TransportHand
|
|||
return TransportType.WEBSOCKET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCreateSession() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SockJsSessionSupport createSession(String sessionId) {
|
||||
throw new IllegalStateException("WebSocket transport handlers do not create new sessions");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleNoSession(ServerHttpRequest request, ServerHttpResponse response) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(ServerHttpRequest request, ServerHttpResponse response,
|
||||
SockJsSessionSupport session) throws Exception {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public class JsonpTransportHandler extends AbstractHttpReceivingTransportHandler
|
|||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(ServerHttpRequest request, ServerHttpResponse response,
|
||||
public void handleRequestInternal(ServerHttpRequest request, ServerHttpResponse response,
|
||||
SockJsSessionSupport sockJsSession) throws Exception {
|
||||
|
||||
if (MediaType.APPLICATION_FORM_URLENCODED.equals(request.getHeaders().getContentType())) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue