Polishing

This commit is contained in:
Juergen Hoeller 2014-08-22 22:55:57 +02:00
parent 28a966f544
commit b93dd95475
9 changed files with 108 additions and 113 deletions

View File

@ -26,14 +26,14 @@ package org.springframework.messaging;
*/ */
public interface Message<T> { public interface Message<T> {
/**
* Return message headers for the message (never {@code null}).
*/
MessageHeaders getHeaders();
/** /**
* Return the message payload. * Return the message payload.
*/ */
T getPayload(); T getPayload();
/**
* Return message headers for the message (never {@code null} but may be empty).
*/
MessageHeaders getHeaders();
} }

View File

@ -59,7 +59,7 @@ import org.springframework.util.IdGenerator;
* </pre> * </pre>
* *
* A third option is to use {@link org.springframework.messaging.support.MessageHeaderAccessor} * A third option is to use {@link org.springframework.messaging.support.MessageHeaderAccessor}
* or one of its sub-classes to create specific categories of headers. * or one of its subclasses to create specific categories of headers.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Mark Fisher * @author Mark Fisher
@ -177,6 +177,7 @@ public class MessageHeaders implements Map<String, Object>, Serializable {
return (T) value; return (T) value;
} }
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
return (this == other || return (this == other ||
@ -232,28 +233,32 @@ public class MessageHeaders implements Map<String, Object>, Serializable {
// Unsupported Map operations // Unsupported Map operations
/** /**
* Since MessageHeaders are immutable, the call to this method will result in {@link UnsupportedOperationException}. * Since MessageHeaders are immutable, the call to this method
* will result in {@link UnsupportedOperationException}.
*/ */
public Object put(String key, Object value) { public Object put(String key, Object value) {
throw new UnsupportedOperationException("MessageHeaders is immutable"); throw new UnsupportedOperationException("MessageHeaders is immutable");
} }
/** /**
* Since MessageHeaders are immutable, the call to this method will result in {@link UnsupportedOperationException}. * Since MessageHeaders are immutable, the call to this method
* will result in {@link UnsupportedOperationException}.
*/ */
public void putAll(Map<? extends String, ? extends Object> t) { public void putAll(Map<? extends String, ? extends Object> map) {
throw new UnsupportedOperationException("MessageHeaders is immutable"); throw new UnsupportedOperationException("MessageHeaders is immutable");
} }
/** /**
* Since MessageHeaders are immutable, the call to this method will result in {@link UnsupportedOperationException}. * Since MessageHeaders are immutable, the call to this method
* will result in {@link UnsupportedOperationException}.
*/ */
public Object remove(Object key) { public Object remove(Object key) {
throw new UnsupportedOperationException("MessageHeaders is immutable"); throw new UnsupportedOperationException("MessageHeaders is immutable");
} }
/** /**
* Since MessageHeaders are immutable, the call to this method will result in {@link UnsupportedOperationException}. * Since MessageHeaders are immutable, the call to this method
* will result in {@link UnsupportedOperationException}.
*/ */
public void clear() { public void clear() {
throw new UnsupportedOperationException("MessageHeaders is immutable"); throw new UnsupportedOperationException("MessageHeaders is immutable");

View File

@ -16,17 +16,16 @@
package org.springframework.messaging.support; package org.springframework.messaging.support;
import org.springframework.messaging.MessageHeaders;
import java.util.Map; import java.util.Map;
import org.springframework.messaging.MessageHeaders;
/** /**
* A {@link GenericMessage} with a {@link Throwable} payload. * A {@link GenericMessage} with a {@link Throwable} payload.
* *
* @author Mark Fisher * @author Mark Fisher
* @author Oleg Zhurakousky * @author Oleg Zhurakousky
* @since 4.0 * @since 4.0
*
* @see MessageBuilder * @see MessageBuilder
*/ */
public class ErrorMessage extends GenericMessage<Throwable> { public class ErrorMessage extends GenericMessage<Throwable> {
@ -36,8 +35,7 @@ public class ErrorMessage extends GenericMessage<Throwable> {
/** /**
* Create a new message with the given payload. * Create a new message with the given payload.
* * @param payload the message payload (never {@code null})
* @param payload the message payload, never {@code null}
*/ */
public ErrorMessage(Throwable payload) { public ErrorMessage(Throwable payload) {
super(payload); super(payload);
@ -46,8 +44,7 @@ public class ErrorMessage extends GenericMessage<Throwable> {
/** /**
* Create a new message with the given payload and headers. * Create a new message with the given payload and headers.
* The content of the given header map is copied. * The content of the given header map is copied.
* * @param payload the message payload (never {@code null})
* @param payload the message payload, never {@code null}
* @param headers message headers to use for initialization * @param headers message headers to use for initialization
*/ */
public ErrorMessage(Throwable payload, Map<String, Object> headers) { public ErrorMessage(Throwable payload, Map<String, Object> headers) {
@ -56,11 +53,9 @@ public class ErrorMessage extends GenericMessage<Throwable> {
/** /**
* A constructor with the {@link MessageHeaders} instance to use. * A constructor with the {@link MessageHeaders} instance to use.
* * <p><strong>Note:</strong> the given {@code MessageHeaders} instance
* <p><strong>Note:</strong> the given {@code MessageHeaders} instance is used * is used directly in the new message, i.e. it is not copied.
* directly in the new message, i.e. it is not copied. * @param payload the message payload (never {@code null})
*
* @param payload the message payload, never {@code null}
* @param headers message headers * @param headers message headers
*/ */
public ErrorMessage(Throwable payload, MessageHeaders headers) { public ErrorMessage(Throwable payload, MessageHeaders headers) {

View File

@ -42,18 +42,18 @@ public class ExecutorSubscribableChannel extends AbstractSubscribableChannel {
/** /**
* Create a new {@link ExecutorSubscribableChannel} instance where messages will be sent * Create a new {@link ExecutorSubscribableChannel} instance
* in the callers thread. * where messages will be sent in the callers thread.
*/ */
public ExecutorSubscribableChannel() { public ExecutorSubscribableChannel() {
this(null); this(null);
} }
/** /**
* Create a new {@link ExecutorSubscribableChannel} instance where messages will be sent * Create a new {@link ExecutorSubscribableChannel} instance
* via the specified executor. * where messages will be sent via the specified executor.
* @param executor the executor used to send the message or {@code null} to execute in * @param executor the executor used to send the message,
* the callers thread. * or {@code null} to execute in the callers thread.
*/ */
public ExecutorSubscribableChannel(Executor executor) { public ExecutorSubscribableChannel(Executor executor) {
this.executor = executor; this.executor = executor;
@ -100,6 +100,45 @@ public class ExecutorSubscribableChannel extends AbstractSubscribableChannel {
} }
/**
* Helps with the invocation of configured executor channel interceptors.
*/
private class ExecutorChannelInterceptorChain {
private int interceptorIndex = -1;
public Message<?> applyBeforeHandle(Message<?> message, MessageChannel channel, MessageHandler handler) {
for (ExecutorChannelInterceptor interceptor : executorInterceptors) {
message = interceptor.beforeHandle(message, channel, handler);
if (message == null) {
String name = interceptor.getClass().getSimpleName();
if (logger.isDebugEnabled()) {
logger.debug(name + " returned null from beforeHandle, i.e. precluding the send.");
}
triggerAfterMessageHandled(message, channel, handler, null);
return null;
}
this.interceptorIndex++;
}
return message;
}
public void triggerAfterMessageHandled(Message<?> message, MessageChannel channel,
MessageHandler handler, Exception ex) {
for (int i = this.interceptorIndex; i >= 0; i--) {
ExecutorChannelInterceptor interceptor = executorInterceptors.get(i);
try {
interceptor.afterMessageHandled(message, channel, handler, ex);
}
catch (Throwable ex2) {
logger.error("Exception from afterMessageHandled in " + interceptor, ex2);
}
}
}
}
/** /**
* Helps with the invocation of the target MessageHandler and interceptors. * Helps with the invocation of the target MessageHandler and interceptors.
*/ */
@ -113,7 +152,6 @@ public class ExecutorSubscribableChannel extends AbstractSubscribableChannel {
private final ExecutorChannelInterceptorChain chain; private final ExecutorChannelInterceptorChain chain;
public SendTask(Message<?> message, MessageChannel channel, MessageHandler handler, public SendTask(Message<?> message, MessageChannel channel, MessageHandler handler,
ExecutorChannelInterceptorChain chain) { ExecutorChannelInterceptorChain chain) {
@ -151,43 +189,4 @@ public class ExecutorSubscribableChannel extends AbstractSubscribableChannel {
} }
} }
/**
* Helps with the invocation of configured executor channel interceptors.
*/
private class ExecutorChannelInterceptorChain {
private int interceptorIndex = -1;
public Message<?> applyBeforeHandle(Message<?> message, MessageChannel channel, MessageHandler handler) {
for (ExecutorChannelInterceptor interceptor : executorInterceptors) {
message = interceptor.beforeHandle(message, channel, handler);
if (message == null) {
String name = interceptor.getClass().getSimpleName();
if (logger.isDebugEnabled()) {
logger.debug(name + " returned null from beforeHandle, i.e. precluding the send.");
}
triggerAfterMessageHandled(message, channel, handler, null);
return null;
}
this.interceptorIndex++;
}
return message;
}
public void triggerAfterMessageHandled(Message<?> message, MessageChannel channel,
MessageHandler handler, Exception ex) {
for (int i = this.interceptorIndex; i >= 0; i--) {
ExecutorChannelInterceptor interceptor = executorInterceptors.get(i);
try {
interceptor.afterMessageHandled(message, channel, handler, ex);
}
catch (Throwable ex2) {
logger.error("Exception from afterMessageHandled in " + interceptor, ex2);
}
}
}
}
} }

View File

@ -30,7 +30,6 @@ import org.springframework.util.ObjectUtils;
* *
* @author Mark Fisher * @author Mark Fisher
* @since 4.0 * @since 4.0
*
* @see MessageBuilder * @see MessageBuilder
*/ */
public class GenericMessage<T> implements Message<T>, Serializable { public class GenericMessage<T> implements Message<T>, Serializable {
@ -45,8 +44,7 @@ public class GenericMessage<T> implements Message<T>, Serializable {
/** /**
* Create a new message with the given payload. * Create a new message with the given payload.
* * @param payload the message payload (never {@code null})
* @param payload the message payload, never {@code null}
*/ */
public GenericMessage(T payload) { public GenericMessage(T payload) {
this(payload, new MessageHeaders(null)); this(payload, new MessageHeaders(null));
@ -55,8 +53,7 @@ public class GenericMessage<T> implements Message<T>, Serializable {
/** /**
* Create a new message with the given payload and headers. * Create a new message with the given payload and headers.
* The content of the given header map is copied. * The content of the given header map is copied.
* * @param payload the message payload (never {@code null})
* @param payload the message payload, never {@code null}
* @param headers message headers to use for initialization * @param headers message headers to use for initialization
*/ */
public GenericMessage(T payload, Map<String, Object> headers) { public GenericMessage(T payload, Map<String, Object> headers) {
@ -65,44 +62,27 @@ public class GenericMessage<T> implements Message<T>, Serializable {
/** /**
* A constructor with the {@link MessageHeaders} instance to use. * A constructor with the {@link MessageHeaders} instance to use.
*
* <p><strong>Note:</strong> the given {@code MessageHeaders} instance is used * <p><strong>Note:</strong> the given {@code MessageHeaders} instance is used
* directly in the new message, i.e. it is not copied. * directly in the new message, i.e. it is not copied.
* * @param payload the message payload (never {@code null})
* @param payload the message payload, never {@code null}
* @param headers message headers * @param headers message headers
*/ */
public GenericMessage(T payload, MessageHeaders headers) { public GenericMessage(T payload, MessageHeaders headers) {
Assert.notNull(payload, "'payload must not be null");
Assert.notNull(headers, "'headers' must not be null"); Assert.notNull(headers, "'headers' must not be null");
Assert.notNull(payload, "payload must not be null");
this.headers = headers;
this.payload = payload; this.payload = payload;
this.headers = headers;
} }
public MessageHeaders getHeaders() {
return this.headers;
}
public T getPayload() { public T getPayload() {
return this.payload; return this.payload;
} }
public String toString() { public MessageHeaders getHeaders() {
StringBuilder sb = new StringBuilder(); return this.headers;
if (this.payload instanceof byte[]) {
sb.append("[Payload byte[").append(((byte[]) this.payload).length).append("]]");
}
else {
sb.append("[Payload=").append(this.payload).append("]");
}
sb.append("[Headers=").append(this.headers).append("]");
return sb.toString();
} }
public int hashCode() {
return this.headers.hashCode() * 23 + ObjectUtils.nullSafeHashCode(this.payload);
}
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) { if (this == obj) {
@ -116,4 +96,20 @@ public class GenericMessage<T> implements Message<T>, Serializable {
return false; return false;
} }
public int hashCode() {
return this.headers.hashCode() * 23 + ObjectUtils.nullSafeHashCode(this.payload);
}
public String toString() {
StringBuilder sb = new StringBuilder(getClass().getSimpleName());
if (this.payload instanceof byte[]) {
sb.append("[payload byte[").append(((byte[]) this.payload).length).append("]]");
}
else {
sb.append("[payload=").append(this.payload).append("]");
}
sb.append("[headers=").append(this.headers).append("]");
return sb.toString();
}
} }

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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.http.server; package org.springframework.http.server;
/** /**
@ -39,17 +40,17 @@ public interface ServerHttpAsyncRequestControl {
void start(long timeout); void start(long timeout);
/** /**
* Whether asynchronous request processing has been started. * Return whether asynchronous request processing has been started.
*/ */
boolean isStarted(); boolean isStarted();
/** /**
* Causes asynchronous request processing to be completed. * Mark asynchronous request processing as completed.
*/ */
void complete(); void complete();
/** /**
* Whether asynchronous request processing has been completed. * Return whether asynchronous request processing has been completed.
*/ */
boolean isCompleted(); boolean isCompleted();

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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -37,6 +37,7 @@ public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncRequ
private static long NO_TIMEOUT_VALUE = Long.MIN_VALUE; private static long NO_TIMEOUT_VALUE = Long.MIN_VALUE;
private final ServletServerHttpRequest request; private final ServletServerHttpRequest request;
private final ServletServerHttpResponse response; private final ServletServerHttpResponse response;
@ -52,7 +53,6 @@ public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncRequ
* respectively. * respectively.
*/ */
public ServletServerHttpAsyncRequestControl(ServletServerHttpRequest request, ServletServerHttpResponse response) { public ServletServerHttpAsyncRequestControl(ServletServerHttpRequest request, ServletServerHttpResponse response) {
Assert.notNull(request, "request is required"); Assert.notNull(request, "request is required");
Assert.notNull(response, "response is required"); Assert.notNull(response, "response is required");
@ -69,7 +69,7 @@ public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncRequ
@Override @Override
public boolean isStarted() { public boolean isStarted() {
return ((this.asyncContext != null) && this.request.getServletRequest().isAsyncStarted()); return (this.asyncContext != null && this.request.getServletRequest().isAsyncStarted());
} }
@Override @Override
@ -84,9 +84,7 @@ public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncRequ
@Override @Override
public void start(long timeout) { public void start(long timeout) {
Assert.state(!isCompleted(), "Async processing has already completed"); Assert.state(!isCompleted(), "Async processing has already completed");
if (isStarted()) { if (isStarted()) {
return; return;
} }
@ -109,6 +107,7 @@ public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncRequ
} }
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Implementation of AsyncListener methods // Implementation of AsyncListener methods
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -120,12 +119,15 @@ public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncRequ
} }
@Override @Override
public void onStartAsync(AsyncEvent event) throws IOException { } public void onStartAsync(AsyncEvent event) throws IOException {
}
@Override @Override
public void onError(AsyncEvent event) throws IOException { } public void onError(AsyncEvent event) throws IOException {
}
@Override @Override
public void onTimeout(AsyncEvent event) throws IOException { } public void onTimeout(AsyncEvent event) throws IOException {
}
} }

View File

@ -45,6 +45,7 @@ import org.springframework.util.Assert;
* {@link ServerHttpRequest} implementation that is based on a {@link HttpServletRequest}. * {@link ServerHttpRequest} implementation that is based on a {@link HttpServletRequest}.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.0 * @since 3.0
*/ */
public class ServletServerHttpRequest implements ServerHttpRequest { public class ServletServerHttpRequest implements ServerHttpRequest {

View File

@ -177,13 +177,11 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
/** /**
* Handle the first request for receiving messages on a SockJS HTTP transport * Handle the first request for receiving messages on a SockJS HTTP transport
* based session. * based session.
*
* <p>Long polling-based transports (e.g. "xhr", "jsonp") complete the request * <p>Long polling-based transports (e.g. "xhr", "jsonp") complete the request
* after writing the open frame. Streaming-based transports ("xhr_streaming", * after writing the open frame. Streaming-based transports ("xhr_streaming",
* "eventsource", and "htmlfile") leave the response open longer for further * "eventsource", and "htmlfile") leave the response open longer for further
* streaming of message frames but will also close it eventually after some * streaming of message frames but will also close it eventually after some
* amount of data has been sent. * amount of data has been sent.
*
* @param request the current request * @param request the current request
* @param response the current response * @param response the current response
* @param frameFormat the transport-specific SocksJS frame format to use * @param frameFormat the transport-specific SocksJS frame format to use
@ -235,13 +233,11 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
/** /**
* Handle all requests, except the first one, to receive messages on a SockJS * Handle all requests, except the first one, to receive messages on a SockJS
* HTTP transport based session. * HTTP transport based session.
*
* <p>Long polling-based transports (e.g. "xhr", "jsonp") complete the request * <p>Long polling-based transports (e.g. "xhr", "jsonp") complete the request
* after writing any buffered message frames (or the next one). Streaming-based * after writing any buffered message frames (or the next one). Streaming-based
* transports ("xhr_streaming", "eventsource", and "htmlfile") leave the * transports ("xhr_streaming", "eventsource", and "htmlfile") leave the
* response open longer for further streaming of message frames but will also * response open longer for further streaming of message frames but will also
* close it eventually after some amount of data has been sent. * close it eventually after some amount of data has been sent.
*
* @param request the current request * @param request the current request
* @param response the current response * @param response the current response
* @param frameFormat the transport-specific SocksJS frame format to use * @param frameFormat the transport-specific SocksJS frame format to use
@ -302,7 +298,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
/** /**
* Called when the connection is active and ready to write to the response. * Called when the connection is active and ready to write to the response.
* Sub-classes should implement but never call this method directly. * Subclasses should implement but never call this method directly.
*/ */
protected abstract void flushCache() throws SockJsTransportFailureException; protected abstract void flushCache() throws SockJsTransportFailureException;