Polishing

This commit is contained in:
Juergen Hoeller 2014-11-07 17:14:50 +01:00
parent 18d2ace785
commit 9ff8a01f29
3 changed files with 57 additions and 47 deletions

View File

@ -36,7 +36,6 @@ import org.springframework.core.io.Resource;
*/
public class PathResourceResolver extends AbstractResourceResolver {
@Override
protected Resource resolveResourceInternal(HttpServletRequest request, String requestPath,
List<? extends Resource> locations, ResourceResolverChain chain) {
@ -55,21 +54,21 @@ public class PathResourceResolver extends AbstractResourceResolver {
for (Resource location : locations) {
try {
if (logger.isTraceEnabled()) {
logger.trace("Checking location=[" + location + "]");
logger.trace("Checking location: " + location);
}
Resource resource = getResource(resourcePath, location);
if (resource != null) {
if (logger.isTraceEnabled()) {
logger.trace("Found match");
logger.trace("Found match: " + resource);
}
return resource;
}
else if (logger.isTraceEnabled()) {
logger.trace("No match");
logger.trace("No match for location: " + location);
}
}
catch (IOException ex) {
logger.trace("Failure checking for relative resource. Trying next location.", ex);
logger.trace("Failure checking for relative resource - trying next location", ex);
}
}
return null;
@ -81,7 +80,7 @@ public class PathResourceResolver extends AbstractResourceResolver {
* {@code Resource} for the given path relative to the location.
* @param resourcePath the path to the resource
* @param location the location to check
* @return the resource or {@code null}
* @return the resource, or {@code null} if none found
*/
protected Resource getResource(String resourcePath, Resource location) throws IOException {
Resource resource = location.createRelative(resourcePath);

View File

@ -61,8 +61,8 @@ public interface WebSocketSession extends Closeable {
/**
* Return a {@link java.security.Principal} instance containing the name of the
* authenticated user. If the user has not been authenticated, the method returns
* <code>null</code>.
* authenticated user.
* <p>If the user has not been authenticated, the method returns <code>null</code>.
*/
Principal getPrincipal();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@ -19,8 +19,10 @@ package org.springframework.web.socket.sockjs.client;
import java.net.URI;
import java.security.Principal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
@ -31,6 +33,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.SettableListenableFuture;
import org.springframework.web.socket.WebSocketHandler;
@ -53,7 +56,6 @@ import org.springframework.web.util.UriComponentsBuilder;
*
* @author Rossen Stoyanchev
* @since 4.1
*
* @see <a href="http://sockjs.org">http://sockjs.org</a>
* @see org.springframework.web.socket.sockjs.client.Transport
*/
@ -64,34 +66,41 @@ public class SockJsClient implements WebSocketClient, Lifecycle {
private static final Log logger = LogFactory.getLog(SockJsClient.class);
private static final Set<String> supportedProtocols = new HashSet<String>(4);
static {
supportedProtocols.add("ws");
supportedProtocols.add("wss");
supportedProtocols.add("http");
supportedProtocols.add("https");
}
private InfoReceiver infoReceiver;
private final List<Transport> transports;
private InfoReceiver infoReceiver;
private SockJsMessageCodec messageCodec;
private TaskScheduler connectTimeoutScheduler;
private final Map<URI, ServerInfo> serverInfoCache = new ConcurrentHashMap<URI, ServerInfo>();
private volatile boolean running = false;
private final Map<URI, ServerInfo> serverInfoCache = new ConcurrentHashMap<URI, ServerInfo>();
/**
* 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.infoReceiver = initInfoReceiver(transports);
this.transports = new ArrayList<Transport>(transports);
this.infoReceiver = initInfoReceiver(transports);
if (jackson2Present) {
this.messageCodec = new Jackson2SockJsMessageCodec();
}
@ -110,21 +119,19 @@ public class SockJsClient implements WebSocketClient, Lifecycle {
/**
* Configure the {@code InfoReceiver} to use to perform the SockJS "Info"
* request before the SockJS session starts.
*
* <p>If the list of transports provided to the constructor contained an
* {@link XhrTransport} or an implementation of {@link InfoReceiver} that
* instance would have been used to initialize this property, or otherwise
* it defaults to {@link RestTemplateXhrTransport}.
*
* @param infoReceiver the transport to use for the SockJS "Info" request
*/
public void setInfoReceiver(InfoReceiver infoReceiver) {
Assert.notNull(infoReceiver, "'infoReceiver' is required");
Assert.notNull(infoReceiver, "InfoReceiver is required");
this.infoReceiver = infoReceiver;
}
/**
* Return the configured {@code InfoReceiver}, never {@code null}.
* Return the configured {@code InfoReceiver} (never {@code null}).
*/
public InfoReceiver getInfoReceiver() {
return this.infoReceiver;
@ -132,17 +139,17 @@ public class SockJsClient implements WebSocketClient, Lifecycle {
/**
* Set the SockJsMessageCodec to use.
*
* <p>By default {@link org.springframework.web.socket.sockjs.frame.Jackson2SockJsMessageCodec
* Jackson2SockJsMessageCodec} is used if Jackson is on the classpath.
*
* @param messageCodec the message messageCodec to use
*/
public void setMessageCodec(SockJsMessageCodec messageCodec) {
Assert.notNull(messageCodec, "'messageCodec' is required");
this.messageCodec = messageCodec;
}
/**
* Return the SockJsMessageCodec to use.
*/
public SockJsMessageCodec getMessageCodec() {
return this.messageCodec;
}
@ -159,6 +166,7 @@ public class SockJsClient implements WebSocketClient, Lifecycle {
this.connectTimeoutScheduler = connectTimeoutScheduler;
}
@Override
public void start() {
if (!isRunning()) {
@ -192,19 +200,10 @@ public class SockJsClient implements WebSocketClient, Lifecycle {
return this.running;
}
/**
* By default the result of a SockJS "Info" request, including whether the
* server has WebSocket disabled and how long the request took (used for
* calculating transport timeout time) is cached. This method can be used to
* clear that cache hence causing it to re-populate.
*/
public void clearServerInfoCache() {
this.serverInfoCache.clear();
}
@Override
public ListenableFuture<WebSocketSession> doHandshake(WebSocketHandler handler,
String uriTemplate, Object... uriVars) {
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();
@ -212,15 +211,16 @@ public class SockJsClient implements WebSocketClient, Lifecycle {
}
@Override
public final ListenableFuture<WebSocketSession> doHandshake(WebSocketHandler handler,
WebSocketHttpHeaders headers, URI url) {
public final ListenableFuture<WebSocketSession> doHandshake(
WebSocketHandler handler, WebSocketHttpHeaders headers, URI url) {
Assert.notNull(handler, "'webSocketHandler' is required");
Assert.notNull(url, "'url' is required");
Assert.notNull(handler, "WebSocketHandler is required");
Assert.notNull(url, "URL is required");
String scheme = url.getScheme();
Assert.isTrue(scheme != null && ("ws".equals(scheme) || "wss".equals(scheme) ||
"http".equals(scheme) || "https".equals(scheme)), "Invalid scheme: " + scheme);
if (!supportedProtocols.contains(scheme)) {
throw new IllegalArgumentException("Invalid scheme: '" + scheme + "'");
}
SettableListenableFuture<WebSocketSession> connectFuture = new SettableListenableFuture<WebSocketSession>();
try {
@ -259,7 +259,10 @@ public class SockJsClient implements WebSocketClient, Lifecycle {
}
}
}
Assert.notEmpty(requests, "No transports, " + urlInfo + ", wsEnabled=" + serverInfo.isWebSocketEnabled());
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);
request.setUser(getUser());
@ -274,15 +277,24 @@ public class SockJsClient implements WebSocketClient, Lifecycle {
/**
* Return the user to associate with the SockJS session and make available via
* {@link org.springframework.web.socket.WebSocketSession#getPrincipal()
* WebSocketSession#getPrincipal()}.
* {@link org.springframework.web.socket.WebSocketSession#getPrincipal()}.
* <p>By default this method returns {@code null}.
* @return the user to associate with the session, possibly {@code null}
* @return the user to associate with the session (possibly {@code null})
*/
protected Principal getUser() {
return null;
}
/**
* By default the result of a SockJS "Info" request, including whether the
* server has WebSocket disabled and how long the request took (used for
* calculating transport timeout time) is cached. This method can be used to
* clear that cache hence causing it to re-populate.
*/
public void clearServerInfoCache() {
this.serverInfoCache.clear();
}
/**
* A simple value object holding the result from a SockJS "Info" request.
@ -293,8 +305,7 @@ public class SockJsClient implements WebSocketClient, Lifecycle {
private final long responseTime;
private ServerInfo(String response, long responseTime) {
public ServerInfo(String response, long responseTime) {
this.responseTime = responseTime;
this.webSocketEnabled = !response.matches(".*[\"']websocket[\"']\\s*:\\s*false.*");
}
@ -308,4 +319,4 @@ public class SockJsClient implements WebSocketClient, Lifecycle {
}
}
}
}