From 458d49bdb8bb9ca56ee114861150624b3d22dd68 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 30 Aug 2016 23:57:11 +0200 Subject: [PATCH] Polishing (cherry picked from commit acbb254) --- .../ApplicationListenerMethodAdapter.java | 22 ++-- .../core/env/AbstractEnvironment.java | 21 ++-- .../simp/stomp/StompHeaderAccessor.java | 2 +- .../messaging/simp/stomp/StompHeaders.java | 21 ++-- .../htmlunit/HtmlUnitRequestBuilder.java | 20 ++-- ...ionListenerMethodTransactionalAdapter.java | 25 ++--- .../org/springframework/http/MediaType.java | 28 ++--- .../web/filter/HttpPutFormContentFilter.java | 15 ++- .../web/util/UriComponentsBuilder.java | 9 +- .../web/socket/WebSocketExtension.java | 105 +++++++++--------- .../AbstractTyrusRequestUpgradeStrategy.java | 2 +- .../standard/ServerEndpointRegistration.java | 5 +- .../TomcatRequestUpgradeStrategy.java | 5 +- 13 files changed, 134 insertions(+), 146 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java b/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java index 243d16428a4..188a5127a94 100644 --- a/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java +++ b/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -77,10 +77,10 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe private EventExpressionEvaluator evaluator; - private String condition; - private EventListener eventListener; + private String condition; + public ApplicationListenerMethodAdapter(String beanName, Class targetClass, Method method) { this.beanName = beanName; @@ -88,7 +88,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe this.targetClass = targetClass; this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); this.declaredEventTypes = resolveDeclaredEventTypes(); - this.methodKey = new AnnotatedElementKey(this.method, this.targetClass); + this.methodKey = new AnnotatedElementKey(method, targetClass); } @@ -165,8 +165,8 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe if (this.method.getParameterTypes().length == 0) { return new Object[0]; } - if (!ApplicationEvent.class.isAssignableFrom(declaredEventType.getRawClass()) - && event instanceof PayloadApplicationEvent) { + if (!ApplicationEvent.class.isAssignableFrom(declaredEventType.getRawClass()) && + event instanceof PayloadApplicationEvent) { return new Object[] {((PayloadApplicationEvent) event).getPayload()}; } else { @@ -213,10 +213,6 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe return true; } - protected A getMethodAnnotation(Class annotationType) { - return AnnotationUtils.findAnnotation(this.method, annotationType); - } - /** * Invoke the event listener method with the given argument values. */ @@ -254,6 +250,10 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe return this.applicationContext.getBean(this.beanName); } + protected A getMethodAnnotation(Class annotationType) { + return AnnotationUtils.findAnnotation(this.method, annotationType); + } + protected EventListener getEventListener() { if (this.eventListener == null) { this.eventListener = AnnotatedElementUtils.findMergedAnnotation(this.method, EventListener.class); @@ -269,7 +269,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe */ protected String getCondition() { if (this.condition == null) { - EventListener eventListener = AnnotatedElementUtils.findMergedAnnotation(this.method, EventListener.class); + EventListener eventListener = getEventListener(); if (eventListener != null) { this.condition = eventListener.condition(); } diff --git a/spring-core/src/main/java/org/springframework/core/env/AbstractEnvironment.java b/spring-core/src/main/java/org/springframework/core/env/AbstractEnvironment.java index c44f5d622f4..f3af8fcd3f5 100644 --- a/spring-core/src/main/java/org/springframework/core/env/AbstractEnvironment.java +++ b/spring-core/src/main/java/org/springframework/core/env/AbstractEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -31,9 +31,6 @@ import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; -import static java.lang.String.*; -import static org.springframework.util.StringUtils.*; - /** * Abstract base class for {@link Environment} implementations. Supports the notion of * reserved default profile names and enables specifying active and default profiles @@ -124,7 +121,7 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { public AbstractEnvironment() { customizePropertySources(this.propertySources); if (this.logger.isDebugEnabled()) { - this.logger.debug(format( + this.logger.debug(String.format( "Initialized %s with PropertySources %s", getClass().getSimpleName(), this.propertySources)); } } @@ -242,7 +239,8 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { if (this.activeProfiles.isEmpty()) { String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME); if (StringUtils.hasText(profiles)) { - setActiveProfiles(commaDelimitedListToStringArray(trimAllWhitespace(profiles))); + setActiveProfiles(StringUtils.commaDelimitedListToStringArray( + StringUtils.trimAllWhitespace(profiles))); } } return this.activeProfiles; @@ -264,7 +262,7 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { @Override public void addActiveProfile(String profile) { if (this.logger.isDebugEnabled()) { - this.logger.debug(format("Activating profile '%s'", profile)); + this.logger.debug(String.format("Activating profile '%s'", profile)); } validateProfile(profile); doGetActiveProfiles(); @@ -296,7 +294,8 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { if (this.defaultProfiles.equals(getReservedDefaultProfiles())) { String profiles = getProperty(DEFAULT_PROFILES_PROPERTY_NAME); if (StringUtils.hasText(profiles)) { - setDefaultProfiles(commaDelimitedListToStringArray(trimAllWhitespace(profiles))); + setDefaultProfiles(StringUtils.commaDelimitedListToStringArray( + StringUtils.trimAllWhitespace(profiles))); } } return this.defaultProfiles; @@ -393,7 +392,7 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { } catch (AccessControlException ex) { if (logger.isInfoEnabled()) { - logger.info(format("Caught AccessControlException when accessing system " + + logger.info(String.format("Caught AccessControlException when accessing system " + "environment variable [%s]; its value will be returned [null]. Reason: %s", attributeName, ex.getMessage())); } @@ -434,7 +433,7 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { } catch (AccessControlException ex) { if (logger.isInfoEnabled()) { - logger.info(format("Caught AccessControlException when accessing system " + + logger.info(String.format("Caught AccessControlException when accessing system " + "property [%s]; its value will be returned [null]. Reason: %s", attributeName, ex.getMessage())); } @@ -574,7 +573,7 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { @Override public String toString() { - return format("%s {activeProfiles=%s, defaultProfiles=%s, propertySources=%s}", + return String.format("%s {activeProfiles=%s, defaultProfiles=%s, propertySources=%s}", getClass().getSimpleName(), this.activeProfiles, this.defaultProfiles, this.propertySources); } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaderAccessor.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaderAccessor.java index c867ec4176e..62b056a9d8f 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaderAccessor.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaderAccessor.java @@ -297,7 +297,7 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor { } public void setHeartbeat(long cx, long cy) { - setNativeHeader(STOMP_HEARTBEAT_HEADER, StringUtils.arrayToCommaDelimitedString(new Object[]{cx, cy})); + setNativeHeader(STOMP_HEARTBEAT_HEADER, cx + "," + cy); } public void setAck(String ack) { diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaders.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaders.java index c6abad4581c..a9f42ca7b36 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaders.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaders.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -223,9 +223,14 @@ public class StompHeaders implements MultiValueMap, Serializable * Applies to the CONNECT and CONNECTED frames. */ public void setHeartbeat(long[] heartbeat) { - Assert.notNull(heartbeat); + if (heartbeat == null || heartbeat.length != 2) { + throw new IllegalArgumentException("Heart-beat array must be of length 2, not " + + (heartbeat != null ? heartbeat.length : "null")); + } String value = heartbeat[0] + "," + heartbeat[1]; - Assert.isTrue(heartbeat[0] >= 0 && heartbeat[1] >= 0, "Heart-beat values cannot be negative: " + value); + if (heartbeat[0] < 0 || heartbeat[1] < 0) { + throw new IllegalArgumentException("Heart-beat values cannot be negative: " + value); + } set(HEARTBEAT, value); } @@ -497,14 +502,8 @@ public class StompHeaders implements MultiValueMap, Serializable @Override public boolean equals(Object other) { - if (this == other) { - return true; - } - if (!(other instanceof StompHeaders)) { - return false; - } - StompHeaders otherHeaders = (StompHeaders) other; - return this.headers.equals(otherHeaders.headers); + return (this == other || (other instanceof StompHeaders && + this.headers.equals(((StompHeaders) other).headers))); } @Override diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java index 4fdaa22a043..40abe8ae775 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java @@ -196,7 +196,8 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { * {@link HttpServletRequest#getContextPath()} which states it can be * an empty string, or it must start with a "/" and not end with a "/". * @param contextPath a valid contextPath - * @throws IllegalArgumentException if the contextPath is not a valid {@link HttpServletRequest#getContextPath()} + * @throws IllegalArgumentException if the contextPath is not a valid + * {@link HttpServletRequest#getContextPath()} */ public void setContextPath(String contextPath) { MockMvcWebConnection.validateContextPath(contextPath); @@ -210,8 +211,7 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { private void authType(MockHttpServletRequest request) { String authorization = header("Authorization"); if (authorization != null) { - String[] authzParts = authorization.split(": "); - request.setAuthType(authzParts[0]); + request.setAuthType(authorization.split(": ")[0]); } } @@ -261,8 +261,8 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { while (tokens.hasMoreTokens()) { String cookieName = tokens.nextToken().trim(); if (!tokens.hasMoreTokens()) { - throw new IllegalArgumentException("Expected value for cookie name '" + cookieName - + "'. Full cookie was " + cookieHeaderValue); + throw new IllegalArgumentException("Expected value for cookie name '" + cookieName + + "'. Full cookie was " + cookieHeaderValue); } String cookieValue = tokens.nextToken().trim(); processCookie(request, cookies, new Cookie(cookieName, cookieValue)); @@ -437,16 +437,12 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { @Override public Object merge(Object parent) { - if (parent == null) { - return this; - } if (parent instanceof RequestBuilder) { this.parentBuilder = (RequestBuilder) parent; + if (parent instanceof SmartRequestBuilder) { + this.parentPostProcessor = (SmartRequestBuilder) parent; + } } - if (parent instanceof SmartRequestBuilder) { - this.parentPostProcessor = (SmartRequestBuilder) parent; - } - return this; } diff --git a/spring-tx/src/main/java/org/springframework/transaction/event/ApplicationListenerMethodTransactionalAdapter.java b/spring-tx/src/main/java/org/springframework/transaction/event/ApplicationListenerMethodTransactionalAdapter.java index 6228d01cb9a..d676d94ade0 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/event/ApplicationListenerMethodTransactionalAdapter.java +++ b/spring-tx/src/main/java/org/springframework/transaction/event/ApplicationListenerMethodTransactionalAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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,9 +18,6 @@ package org.springframework.transaction.event; import java.lang.reflect.Method; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - import org.springframework.context.ApplicationEvent; import org.springframework.context.event.ApplicationListenerMethodAdapter; import org.springframework.context.event.EventListener; @@ -35,20 +32,19 @@ import org.springframework.transaction.support.TransactionSynchronizationManager * an event to a {@link TransactionalEventListener} annotated method. Supports * the exact same features as any regular {@link EventListener} annotated method * but is aware of the transactional context of the event publisher. - *

- * Processing of {@link TransactionalEventListener} is enabled automatically when - * Spring's transaction management is enabled. For other cases, registering a - * bean of type {@link TransactionalEventListenerFactory} is required. + * + *

Processing of {@link TransactionalEventListener} is enabled automatically + * when Spring's transaction management is enabled. For other cases, registering + * a bean of type {@link TransactionalEventListenerFactory} is required. * * @author Stephane Nicoll + * @author Juergen Hoeller * @since 4.2 * @see ApplicationListenerMethodAdapter * @see TransactionalEventListener */ class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerMethodAdapter { - protected final Log logger = LogFactory.getLog(getClass()); - private final TransactionalEventListener annotation; @@ -65,14 +61,15 @@ class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerM TransactionSynchronizationManager.registerSynchronization(transactionSynchronization); } else if (this.annotation.fallbackExecution()) { - if (this.annotation.phase() == TransactionPhase.AFTER_ROLLBACK) { - logger.warn("Processing '" + event + "' as a fallback execution on AFTER_ROLLBACK phase."); + if (this.annotation.phase() == TransactionPhase.AFTER_ROLLBACK && logger.isWarnEnabled()) { + logger.warn("Processing " + event + " as a fallback execution on AFTER_ROLLBACK phase"); } processEvent(event); } else { + // No transactional event execution at all if (logger.isDebugEnabled()) { - logger.debug("No transaction is running, skipping '" + event + "' for '" + this + "'"); + logger.debug("No transaction is active - skipping " + event); } } } @@ -85,7 +82,7 @@ class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerM TransactionalEventListener annotation = AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class); if (annotation == null) { - throw new IllegalStateException("No TransactionalEventListener annotation found on '" + method + "'"); + throw new IllegalStateException("No TransactionalEventListener annotation found on method: " + method); } return annotation; } diff --git a/spring-web/src/main/java/org/springframework/http/MediaType.java b/spring-web/src/main/java/org/springframework/http/MediaType.java index 8b8e04853f8..b23239dbc9c 100644 --- a/spring-web/src/main/java/org/springframework/http/MediaType.java +++ b/spring-web/src/main/java/org/springframework/http/MediaType.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -42,8 +42,7 @@ import org.springframework.util.comparator.CompoundComparator; * @author Rossen Stoyanchev * @author Sebastien Deleuze * @since 3.0 - * @see HTTP 1.1: Semantics - * and Content, section 3.1.1.1 + * @see HTTP 1.1: Semantics and Content, section 3.1.1.1 */ public class MediaType extends MimeType implements Serializable { @@ -71,7 +70,7 @@ public class MediaType extends MimeType implements Serializable { /** * Public constant media type for {@code application/x-www-form-urlencoded}. - * */ + */ public final static MediaType APPLICATION_FORM_URLENCODED; /** @@ -103,7 +102,7 @@ public class MediaType extends MimeType implements Serializable { /** * Public constant media type for {@code application/octet-stream}. - * */ + */ public final static MediaType APPLICATION_OCTET_STREAM; /** @@ -113,7 +112,7 @@ public class MediaType extends MimeType implements Serializable { /** * Public constant media type for {@code application/xhtml+xml}. - * */ + */ public final static MediaType APPLICATION_XHTML_XML; /** @@ -163,7 +162,7 @@ public class MediaType extends MimeType implements Serializable { /** * Public constant media type for {@code multipart/form-data}. - * */ + */ public final static MediaType MULTIPART_FORM_DATA; /** @@ -173,7 +172,7 @@ public class MediaType extends MimeType implements Serializable { /** * Public constant media type for {@code text/html}. - * */ + */ public final static MediaType TEXT_HTML; /** @@ -183,7 +182,7 @@ public class MediaType extends MimeType implements Serializable { /** * Public constant media type for {@code text/plain}. - * */ + */ public final static MediaType TEXT_PLAIN; /** @@ -193,7 +192,7 @@ public class MediaType extends MimeType implements Serializable { /** * Public constant media type for {@code text/xml}. - * */ + */ public final static MediaType TEXT_XML; /** @@ -364,6 +363,8 @@ public class MediaType extends MimeType implements Serializable { * Parse the given String value into a {@code MediaType} object, * with this method name following the 'valueOf' naming convention * (as supported by {@link org.springframework.core.convert.ConversionService}. + * @param value the string to parse + * @throws InvalidMediaTypeException if the media type value cannot be parsed * @see #parseMediaType(String) */ public static MediaType valueOf(String value) { @@ -374,7 +375,7 @@ public class MediaType extends MimeType implements Serializable { * Parse the given String into a single {@code MediaType}. * @param mediaType the string to parse * @return the media type - * @throws InvalidMediaTypeException if the string cannot be parsed + * @throws InvalidMediaTypeException if the media type value cannot be parsed */ public static MediaType parseMediaType(String mediaType) { MimeType type; @@ -392,13 +393,12 @@ public class MediaType extends MimeType implements Serializable { } } - /** - * Parse the given, comma-separated string into a list of {@code MediaType} objects. + * Parse the given comma-separated string into a list of {@code MediaType} objects. *

This method can be used to parse an Accept or Content-Type header. * @param mediaTypes the string to parse * @return the list of media types - * @throws IllegalArgumentException if the string cannot be parsed + * @throws InvalidMediaTypeException if the media type value cannot be parsed */ public static List parseMediaTypes(String mediaTypes) { if (!StringUtils.hasLength(mediaTypes)) { diff --git a/spring-web/src/main/java/org/springframework/web/filter/HttpPutFormContentFilter.java b/spring-web/src/main/java/org/springframework/web/filter/HttpPutFormContentFilter.java index 74664a9cca0..8d672b5a10c 100644 --- a/spring-web/src/main/java/org/springframework/web/filter/HttpPutFormContentFilter.java +++ b/spring-web/src/main/java/org/springframework/web/filter/HttpPutFormContentFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2016 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. @@ -61,6 +61,7 @@ public class HttpPutFormContentFilter extends OncePerRequestFilter { private final FormHttpMessageConverter formConverter = new AllEncompassingFormHttpMessageConverter(); + /** * The default character set to use for reading form data. */ @@ -68,6 +69,7 @@ public class HttpPutFormContentFilter extends OncePerRequestFilter { this.formConverter.setCharset(charset); } + @Override protected void doFilterInternal(final HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { @@ -104,29 +106,30 @@ public class HttpPutFormContentFilter extends OncePerRequestFilter { } } + private static class HttpPutFormContentRequestWrapper extends HttpServletRequestWrapper { private MultiValueMap formParameters; public HttpPutFormContentRequestWrapper(HttpServletRequest request, MultiValueMap parameters) { super(request); - this.formParameters = (parameters != null) ? parameters : new LinkedMultiValueMap(); + this.formParameters = (parameters != null ? parameters : new LinkedMultiValueMap()); } @Override public String getParameter(String name) { String queryStringValue = super.getParameter(name); String formValue = this.formParameters.getFirst(name); - return (queryStringValue != null) ? queryStringValue : formValue; + return (queryStringValue != null ? queryStringValue : formValue); } @Override public Map getParameterMap() { Map result = new LinkedHashMap(); - Enumeration names = this.getParameterNames(); + Enumeration names = getParameterNames(); while (names.hasMoreElements()) { String name = names.nextElement(); - result.put(name, this.getParameterValues(name)); + result.put(name, getParameterValues(name)); } return result; } @@ -150,7 +153,7 @@ public class HttpPutFormContentFilter extends OncePerRequestFilter { return formValues.toArray(new String[formValues.size()]); } else { - List result = new ArrayList(); + List result = new ArrayList(queryStringValues.length + formValues.size()); result.addAll(Arrays.asList(queryStringValues)); result.addAll(formValues); return result.toArray(new String[result.size()]); diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java index 44eb0a07e49..3c3251deec8 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java @@ -686,8 +686,7 @@ public class UriComponentsBuilder implements Cloneable { else { String hostHeader = headers.getFirst("X-Forwarded-Host"); if (StringUtils.hasText(hostHeader)) { - String[] hosts = StringUtils.commaDelimitedListToStringArray(hostHeader); - String hostToUse = hosts[0]; + String hostToUse = StringUtils.commaDelimitedListToStringArray(hostHeader)[0]; if (hostToUse.contains(":")) { String[] hostAndPort = StringUtils.split(hostToUse, ":"); host(hostAndPort[0]); @@ -701,14 +700,12 @@ public class UriComponentsBuilder implements Cloneable { String portHeader = headers.getFirst("X-Forwarded-Port"); if (StringUtils.hasText(portHeader)) { - String[] ports = StringUtils.commaDelimitedListToStringArray(portHeader); - port(Integer.parseInt(ports[0])); + port(Integer.parseInt(StringUtils.commaDelimitedListToStringArray(portHeader)[0])); } String protocolHeader = headers.getFirst("X-Forwarded-Proto"); if (StringUtils.hasText(protocolHeader)) { - String[] protocols = StringUtils.commaDelimitedListToStringArray(protocolHeader); - scheme(protocols[0]); + scheme(StringUtils.commaDelimitedListToStringArray(protocolHeader)[0]); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketExtension.java b/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketExtension.java index 4ec0fe803b3..e43a1d2a82a 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketExtension.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 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. @@ -44,6 +44,7 @@ import org.springframework.util.StringUtils; * e.g. extensions "foo, bar" will be executed as "bar(foo(message))".

* * @author Brian Clozel + * @author Juergen Hoeller * @since 4.0 * @see WebSocket Protocol Extensions, RFC 6455 - Section 9 */ @@ -68,54 +69,90 @@ public class WebSocketExtension { * @param parameters the parameters */ public WebSocketExtension(String name, Map parameters) { - Assert.hasLength(name, "extension name must not be empty"); + Assert.hasLength(name, "Extension name must not be empty"); this.name = name; if (!CollectionUtils.isEmpty(parameters)) { - Map m = new LinkedCaseInsensitiveMap(parameters.size(), Locale.ENGLISH); - m.putAll(parameters); - this.parameters = Collections.unmodifiableMap(m); + Map map = new LinkedCaseInsensitiveMap(parameters.size(), Locale.ENGLISH); + map.putAll(parameters); + this.parameters = Collections.unmodifiableMap(map); } else { this.parameters = Collections.emptyMap(); } } + /** - * @return the name of the extension + * Return the name of the extension (never {@code null) or empty}. */ public String getName() { return this.name; } /** - * @return the parameters of the extension, never {@code null} + * Return the parameters of the extension (never {@code null}). */ public Map getParameters() { return this.parameters; } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + WebSocketExtension otherExt = (WebSocketExtension) other; + return (this.name.equals(otherExt.name) && this.parameters.equals(otherExt.parameters)); + } + + @Override + public int hashCode() { + return this.name.hashCode() * 31 + this.parameters.hashCode(); + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + str.append(this.name); + for (Map.Entry entry : this.parameters.entrySet()) { + str.append(';'); + str.append(entry.getKey()); + str.append('='); + str.append(entry.getValue()); + } + return str.toString(); + } + + /** * Parse the given, comma-separated string into a list of {@code WebSocketExtension} objects. - *

This method can be used to parse a "Sec-WebSocket-Extension" extensions. + *

This method can be used to parse a "Sec-WebSocket-Extension" header. * @param extensions the string to parse * @return the list of extensions * @throws IllegalArgumentException if the string cannot be parsed */ public static List parseExtensions(String extensions) { - if (extensions == null || !StringUtils.hasText(extensions)) { - return Collections.emptyList(); - } - else { - List result = new ArrayList(); - for (String token : extensions.split(",")) { + if (StringUtils.hasText(extensions)) { + String[] tokens = StringUtils.tokenizeToStringArray(extensions, ","); + List result = new ArrayList(tokens.length); + for (String token : tokens) { result.add(parseExtension(token)); } return result; } + else { + return Collections.emptyList(); + } } private static WebSocketExtension parseExtension(String extension) { - Assert.doesNotContain(extension, ",", "Expected a single extension value: " + extension); + if (extension.contains(",")) { + throw new IllegalArgumentException("Expected single extension value: [" + extension + "]"); + } String[] parts = StringUtils.tokenizeToStringArray(extension, ";"); String name = parts[0].trim(); @@ -136,42 +173,4 @@ public class WebSocketExtension { return new WebSocketExtension(name, parameters); } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if ((o == null) || (getClass() != o.getClass())) { - return false; - } - WebSocketExtension that = (WebSocketExtension) o; - if (!name.equals(that.name)) { - return false; - } - if (!parameters.equals(that.parameters)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - int result = name.hashCode(); - result = 31 * result + parameters.hashCode(); - return result; - } - - @Override - public String toString() { - StringBuilder str = new StringBuilder(); - str.append(this.name); - for (String param : parameters.keySet()) { - str.append(';'); - str.append(param); - str.append('='); - str.append(this.parameters.get(param)); - } - return str.toString(); - } - } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/AbstractTyrusRequestUpgradeStrategy.java b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/AbstractTyrusRequestUpgradeStrategy.java index 35886efc724..9d62b4c573d 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/AbstractTyrusRequestUpgradeStrategy.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/AbstractTyrusRequestUpgradeStrategy.java @@ -76,7 +76,7 @@ public abstract class AbstractTyrusRequestUpgradeStrategy extends AbstractStanda @Override public String[] getSupportedVersions() { - return StringUtils.commaDelimitedListToStringArray(Version.getSupportedWireProtocolVersions()); + return StringUtils.tokenizeToStringArray(Version.getSupportedWireProtocolVersions(), ","); } protected List getInstalledExtensions(WebSocketContainer container) { diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServerEndpointRegistration.java b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServerEndpointRegistration.java index 5e066de54e7..4b2afc5f03d 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServerEndpointRegistration.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/ServerEndpointRegistration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 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. @@ -107,8 +107,7 @@ public class ServerEndpointRegistration extends ServerEndpointConfig.Configurato @Override public Class getEndpointClass() { - return (this.endpoint != null) ? - this.endpoint.getClass() : ((Class) this.endpointProvider.getHandlerType()); + return (this.endpoint != null ? this.endpoint.getClass() : this.endpointProvider.getHandlerType()); } public Endpoint getEndpoint() { diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/TomcatRequestUpgradeStrategy.java b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/TomcatRequestUpgradeStrategy.java index 9ae54f9924c..0948aec5b73 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/TomcatRequestUpgradeStrategy.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/server/standard/TomcatRequestUpgradeStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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,7 +17,6 @@ package org.springframework.web.socket.server.standard; import java.io.IOException; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -65,7 +64,7 @@ public class TomcatRequestUpgradeStrategy extends AbstractStandardUpgradeStrateg Map pathParams = Collections. emptyMap(); ServerEndpointRegistration endpointConfig = new ServerEndpointRegistration(path, endpoint); - endpointConfig.setSubprotocols(Arrays.asList(selectedProtocol)); + endpointConfig.setSubprotocols(Collections.singletonList(selectedProtocol)); endpointConfig.setExtensions(selectedExtensions); try {