diff --git a/org.springframework.web.portlet/.classpath b/org.springframework.web.portlet/.classpath
index 6ad70b93a7c1a47090bcf2e4e9edae459e22e3e9..f272084009af4d92b70d982a8c81b6377e2c2459 100644
--- a/org.springframework.web.portlet/.classpath
+++ b/org.springframework.web.portlet/.classpath
@@ -10,7 +10,7 @@
-
+
diff --git a/org.springframework.web.portlet/ivy.xml b/org.springframework.web.portlet/ivy.xml
index 08cc3ab4186d4a2f1ff25518bb1b33a982972184..6bd790f1297570dcdce8cd2ea2acfd323608ed92 100644
--- a/org.springframework.web.portlet/ivy.xml
+++ b/org.springframework.web.portlet/ivy.xml
@@ -21,7 +21,7 @@
-
+
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/DispatcherPortlet.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/DispatcherPortlet.java
index 144fdfef6aadd23a7c43942699960628d7340e81..70b586a9c60adaed84b3482fae163a7830f28549 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/DispatcherPortlet.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/DispatcherPortlet.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -26,12 +26,17 @@ import java.util.Map;
import java.util.Properties;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
+import javax.portlet.EventRequest;
+import javax.portlet.EventResponse;
+import javax.portlet.MimeResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
import javax.portlet.UnavailableException;
import org.apache.commons.logging.Log;
@@ -42,18 +47,12 @@ import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
-import org.springframework.context.i18n.LocaleContext;
-import org.springframework.context.i18n.LocaleContextHolder;
-import org.springframework.context.i18n.SimpleLocaleContext;
import org.springframework.core.OrderComparator;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
-import org.springframework.web.context.request.RequestAttributes;
-import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.multipart.MultipartException;
-import org.springframework.web.portlet.context.PortletRequestAttributes;
import org.springframework.web.portlet.multipart.MultipartActionRequest;
import org.springframework.web.portlet.multipart.PortletMultipartResolver;
import org.springframework.web.servlet.View;
@@ -74,17 +73,15 @@ import org.springframework.web.servlet.ViewResolver;
*
*
It can use any {@link HandlerMapping} implementation - pre-built or provided
* as part of an application - to control the routing of requests to handler objects.
- * Default is a {@link org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping}
- * on Java 5+; there is no default on Java 1.4. HandlerMapping objects can be defined as
- * beans in the portlet's application context, implementing the HandlerMapping interface,
- * overriding the default HandlerMapping if present. HandlerMappings can be given any
- * bean name (they are tested by type).
+ * Default is a {@link org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping}.
+ * HandlerMapping objects can be defined as beans in the portlet's application context,
+ * implementing the HandlerMapping interface, overriding the default HandlerMapping if present.
+ * HandlerMappings can be given any bean name (they are tested by type).
*
*
It can use any {@link HandlerAdapter}; this allows for using any handler interface.
* The default adapter is {@link org.springframework.web.portlet.mvc.SimpleControllerHandlerAdapter}
* for Spring's {@link org.springframework.web.portlet.mvc.Controller} interface.
- * When running in a Java 5+ environment, a default
- * {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter}
+ * A default {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter}
* will be registered as well. HandlerAdapter objects can be added as beans in the
* application context, overriding the default HandlerAdapter. Like HandlerMappings,
* HandlerAdapters can be given any bean name (they are tested by type).
@@ -253,9 +250,6 @@ public class DispatcherPortlet extends FrameworkPortlet {
/** URL that points to the ViewRendererServlet */
private String viewRendererUrl = DEFAULT_VIEW_RENDERER_URL;
- /** Expose LocaleContext and RequestAttributes as inheritable for child threads? */
- private boolean threadContextInheritable = false;
-
/** MultipartResolver used by this portlet */
private PortletMultipartResolver multipartResolver;
@@ -325,22 +319,6 @@ public class DispatcherPortlet extends FrameworkPortlet {
this.viewRendererUrl = viewRendererUrl;
}
- /**
- * Set whether to expose the LocaleContext and RequestAttributes as inheritable
- * for child threads (using an {@link java.lang.InheritableThreadLocal}).
- *
Default is "false", to avoid side effects on spawned background threads.
- * Switch this to "true" to enable inheritance for custom child threads which
- * are spawned during request processing and only used for this request
- * (that is, ending after their initial task, without reuse of the thread).
- *
WARNING: Do not use inheritance for child threads if you are
- * accessing a thread pool which is configured to potentially add new threads
- * on demand (e.g. a JDK {@link java.util.concurrent.ThreadPoolExecutor}),
- * since this will expose the inherited context to such a pooled thread.
- */
- public void setThreadContextInheritable(boolean threadContextInheritable) {
- this.threadContextInheritable = threadContextInheritable;
- }
-
/**
* This implementation calls {@link #initStrategies}.
@@ -638,19 +616,6 @@ public class DispatcherPortlet extends FrameworkPortlet {
logger.debug("DispatcherPortlet with name '" + getPortletName() + "' received action request");
}
- // Expose current LocaleResolver and request as LocaleContext.
- LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
- LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable);
-
- // Expose current RequestAttributes to current thread.
- RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();
- PortletRequestAttributes requestAttributes = new PortletRequestAttributes(request);
- RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
-
- if (logger.isDebugEnabled()) {
- logger.debug("Bound action request context to thread: " + request);
- }
-
ActionRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
int interceptorIndex = -1;
@@ -713,16 +678,6 @@ public class DispatcherPortlet extends FrameworkPortlet {
if (processedRequest instanceof MultipartActionRequest && processedRequest != request) {
this.multipartResolver.cleanupMultipart((MultipartActionRequest) processedRequest);
}
-
- // Reset thread-bound context.
- RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable);
- LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);
-
- // Clear request attributes.
- requestAttributes.requestCompleted();
- if (logger.isDebugEnabled()) {
- logger.debug("Cleared thread-bound action request context: " + request);
- }
}
}
@@ -741,19 +696,6 @@ public class DispatcherPortlet extends FrameworkPortlet {
logger.debug("DispatcherPortlet with name '" + getPortletName() + "' received render request");
}
- // Expose current LocaleResolver and request as LocaleContext.
- LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
- LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable);
-
- // Expose current RequestAttributes to current thread.
- RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();
- PortletRequestAttributes requestAttributes = new PortletRequestAttributes(request);
- RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
-
- if (logger.isDebugEnabled()) {
- logger.debug("Bound render request context to thread: " + request);
- }
-
HandlerExecutionChain mappedHandler = null;
int interceptorIndex = -1;
@@ -843,31 +785,185 @@ public class DispatcherPortlet extends FrameworkPortlet {
triggerAfterRenderCompletion(mappedHandler, interceptorIndex, request, response, ex);
throw ex;
}
+ }
- finally {
- // Reset thread-bound context.
- RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable);
- LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);
+ /**
+ * Processes the actual dispatching to the handler for resource requests.
+ *
The handler will be obtained by applying the portlet's HandlerMappings in order.
+ * The HandlerAdapter will be obtained by querying the portlet's installed
+ * HandlerAdapters to find the first that supports the handler class.
+ * @param request current portlet render request
+ * @param response current portlet render response
+ * @throws Exception in case of any kind of processing failure
+ */
+ @Override
+ protected void doResourceService(ResourceRequest request, ResourceResponse response) throws Exception {
+ if (logger.isDebugEnabled()) {
+ logger.debug("DispatcherPortlet with name '" + getPortletName() + "' received resource request");
+ }
- // Clear request attributes.
- requestAttributes.requestCompleted();
- if (logger.isDebugEnabled()) {
- logger.debug("Cleared thread-bound render request context: " + request);
+ HandlerExecutionChain mappedHandler = null;
+ int interceptorIndex = -1;
+
+ try {
+ ModelAndView mv = null;
+ try {
+ // Check for forwarded exception from the action phase
+ PortletSession session = request.getPortletSession(false);
+ if (session != null) {
+ if (request.getParameter(ACTION_EXCEPTION_RENDER_PARAMETER) != null) {
+ Exception ex = (Exception) session.getAttribute(ACTION_EXCEPTION_SESSION_ATTRIBUTE);
+ if (ex != null) {
+ logger.debug("Render phase found exception caught during action phase - rethrowing it");
+ throw ex;
+ }
+ }
+ else {
+ session.removeAttribute(ACTION_EXCEPTION_SESSION_ATTRIBUTE);
+ }
+ }
+
+ // Determine handler for the current request.
+ mappedHandler = getHandler(request, false);
+ if (mappedHandler == null || mappedHandler.getHandler() == null) {
+ noHandlerFound(request, response);
+ return;
+ }
+
+ // Apply preHandle methods of registered interceptors.
+ HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
+ if (interceptors != null) {
+ for (int i = 0; i < interceptors.length; i++) {
+ HandlerInterceptor interceptor = interceptors[i];
+ if (!interceptor.preHandleResource(request, response, mappedHandler.getHandler())) {
+ triggerAfterResourceCompletion(mappedHandler, interceptorIndex, request, response, null);
+ return;
+ }
+ interceptorIndex = i;
+ }
+ }
+
+ // Actually invoke the handler.
+ HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
+ mv = ha.handleResource(request, response, mappedHandler.getHandler());
+
+ // Apply postHandle methods of registered interceptors.
+ if (interceptors != null) {
+ for (int i = interceptors.length - 1; i >= 0; i--) {
+ HandlerInterceptor interceptor = interceptors[i];
+ interceptor.postHandleResource(request, response, mappedHandler.getHandler(), mv);
+ }
+ }
+ }
+ catch (ModelAndViewDefiningException ex) {
+ logger.debug("ModelAndViewDefiningException encountered", ex);
+ mv = ex.getModelAndView();
+ }
+ catch (Exception ex) {
+ Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
+ mv = processHandlerException(request, response, handler, ex);
+ }
+
+ // Did the handler return a view to render?
+ if (mv != null && !mv.isEmpty()) {
+ render(mv, request, response);
}
+ else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Null ModelAndView returned to DispatcherPortlet with name '" +
+ getPortletName() + "': assuming HandlerAdapter completed request handling");
+ }
+ }
+
+ // Trigger after-completion for successful outcome.
+ triggerAfterResourceCompletion(mappedHandler, interceptorIndex, request, response, null);
}
- }
+ catch (Exception ex) {
+ // Trigger after-completion for thrown exception.
+ triggerAfterResourceCompletion(mappedHandler, interceptorIndex, request, response, ex);
+ throw ex;
+ }
+ catch (Error err) {
+ PortletException ex =
+ new PortletException("Error occured during request processing: " + err.getMessage(), err);
+ // Trigger after-completion for thrown exception.
+ triggerAfterResourceCompletion(mappedHandler, interceptorIndex, request, response, ex);
+ throw ex;
+ }
+ }
/**
- * Build a LocaleContext for the given request, exposing the request's
- * primary locale as current locale.
- * @param request current HTTP request
- * @return the corresponding LocaleContext
+ * Processes the actual dispatching to the handler for event requests.
+ *
The handler will be obtained by applying the portlet's HandlerMappings in order.
+ * The HandlerAdapter will be obtained by querying the portlet's installed
+ * HandlerAdapters to find the first that supports the handler class.
+ * @param request current portlet action request
+ * @param response current portlet Action response
+ * @throws Exception in case of any kind of processing failure
*/
- protected LocaleContext buildLocaleContext(PortletRequest request) {
- return new SimpleLocaleContext(request.getLocale());
+ @Override
+ protected void doEventService(EventRequest request, EventResponse response) throws Exception {
+ if (logger.isDebugEnabled()) {
+ logger.debug("DispatcherPortlet with name '" + getPortletName() + "' received action request");
+ }
+
+ HandlerExecutionChain mappedHandler = null;
+ int interceptorIndex = -1;
+
+ try {
+ // Determine handler for the current request.
+ mappedHandler = getHandler(request, false);
+ if (mappedHandler == null || mappedHandler.getHandler() == null) {
+ noHandlerFound(request, response);
+ return;
+ }
+
+ // Apply preHandle methods of registered interceptors.
+ HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
+ if (interceptors != null) {
+ for (int i = 0; i < interceptors.length; i++) {
+ HandlerInterceptor interceptor = interceptors[i];
+ if (!interceptor.preHandleEvent(request, response, mappedHandler.getHandler())) {
+ triggerAfterEventCompletion(mappedHandler, interceptorIndex, request, response, null);
+ return;
+ }
+ interceptorIndex = i;
+ }
+ }
+
+ // Actually invoke the handler.
+ HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
+ ha.handleEvent(request, response, mappedHandler.getHandler());
+
+ // Trigger after-completion for successful outcome.
+ triggerAfterEventCompletion(mappedHandler, interceptorIndex, request, response, null);
+ }
+
+ catch (Exception ex) {
+ // Trigger after-completion for thrown exception.
+ triggerAfterEventCompletion(mappedHandler, interceptorIndex, request, response, ex);
+ // Forward the exception to the render phase to be displayed.
+ try {
+ response.setRenderParameter(ACTION_EXCEPTION_RENDER_PARAMETER, ex.toString());
+ request.getPortletSession().setAttribute(ACTION_EXCEPTION_SESSION_ATTRIBUTE, ex);
+ logger.debug("Caught exception during action phase - forwarding to render phase", ex);
+ }
+ catch (IllegalStateException ex2) {
+ // Probably sendRedirect called... need to rethrow exception immediately.
+ throw ex;
+ }
+ }
+ catch (Error err) {
+ PortletException ex =
+ new PortletException("Error occured during request processing: " + err.getMessage(), err);
+ // Trigger after-completion for thrown exception.
+ triggerAfterEventCompletion(mappedHandler, interceptorIndex, request, response, ex);
+ throw ex;
+ }
}
+
/**
* Convert the request into a multipart request, and make multipart resolver available.
* If no multipart resolver is set, simply use the existing request.
@@ -929,11 +1025,11 @@ public class DispatcherPortlet extends FrameworkPortlet {
protected void noHandlerFound(PortletRequest request, PortletResponse response) throws Exception {
if (pageNotFoundLogger.isWarnEnabled()) {
pageNotFoundLogger.warn("No mapping found for current request " +
- "in DispatcherPortlet with name '" + getPortletName() + "'" +
- ", mode '" + request.getPortletMode() + "'" +
- ", type '" + (response instanceof ActionResponse ? "action" : "render") + "'" +
- ", session '" + request.getRequestedSessionId() + "'" +
- ", user '" + getUsernameForRequest(request) + "'");
+ "in DispatcherPortlet with name '" + getPortletName() +
+ "', mode '" + request.getPortletMode() +
+ "', phase '" + request.getAttribute(PortletRequest.LIFECYCLE_PHASE) +
+ "', session '" + request.getRequestedSessionId() +
+ "', user '" + getUsernameForRequest(request) + "'");
}
throw new UnavailableException("No handler found for request");
}
@@ -957,67 +1053,6 @@ public class DispatcherPortlet extends FrameworkPortlet {
"]: Does your handler implement a supported interface like Controller?");
}
- /**
- * Determine an error ModelAndView via the registered HandlerExceptionResolvers.
- * @param request current portlet request
- * @param response current portlet response
- * @param handler the executed handler, or null if none chosen at the time of
- * the exception (for example, if multipart resolution failed)
- * @param ex the exception that got thrown during handler execution
- * @return a corresponding ModelAndView to forward to
- * @throws Exception if no error ModelAndView found
- */
- protected ModelAndView processHandlerException(
- RenderRequest request, RenderResponse response, Object handler, Exception ex)
- throws Exception {
-
- ModelAndView exMv = null;
- for (Iterator it = this.handlerExceptionResolvers.iterator(); exMv == null && it.hasNext();) {
- HandlerExceptionResolver resolver = it.next();
- exMv = resolver.resolveException(request, response, handler, ex);
- }
- if (exMv != null) {
- if (logger.isDebugEnabled()) {
- logger.debug("HandlerExceptionResolver returned ModelAndView [" + exMv + "] for exception");
- }
- logger.warn("Handler execution resulted in exception - forwarding to resolved error view", ex);
- return exMv;
- }
- else {
- throw ex;
- }
- }
-
- /**
- * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
- * Will just invoke afterCompletion for all interceptors whose preHandle
- * invocation has successfully completed and returned true.
- * @param mappedHandler the mapped HandlerExecutionChain
- * @param interceptorIndex index of last interceptor that successfully completed
- * @param ex Exception thrown on handler execution, or null if none
- * @see HandlerInterceptor#afterRenderCompletion
- */
- private void triggerAfterActionCompletion(HandlerExecutionChain mappedHandler, int interceptorIndex,
- ActionRequest request, ActionResponse response, Exception ex)
- throws Exception {
-
- // Apply afterCompletion methods of registered interceptors.
- if (mappedHandler != null) {
- HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
- if (interceptors != null) {
- for (int i = interceptorIndex; i >= 0; i--) {
- HandlerInterceptor interceptor = interceptors[i];
- try {
- interceptor.afterActionCompletion(request, response, mappedHandler.getHandler(), ex);
- }
- catch (Throwable ex2) {
- logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
- }
- }
- }
- }
- }
-
/**
* Render the given ModelAndView. This is the last stage in handling a request.
@@ -1027,7 +1062,7 @@ public class DispatcherPortlet extends FrameworkPortlet {
* @param response current portlet render response
* @throws Exception if there's a problem rendering the view
*/
- protected void render(ModelAndView mv, RenderRequest request, RenderResponse response) throws Exception {
+ protected void render(ModelAndView mv, PortletRequest request, MimeResponse response) throws Exception {
View view = null;
if (mv.isReference()) {
// We need to resolve the view name.
@@ -1087,7 +1122,7 @@ public class DispatcherPortlet extends FrameworkPortlet {
* (typically in case of problems creating an actual View object)
* @see ViewResolver#resolveViewName
*/
- protected View resolveViewName(String viewName, Map model, RenderRequest request) throws Exception {
+ protected View resolveViewName(String viewName, Map model, PortletRequest request) throws Exception {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, request.getLocale());
if (view != null) {
@@ -1107,7 +1142,7 @@ public class DispatcherPortlet extends FrameworkPortlet {
* @param response current portlet render response
* @throws Exception if there's a problem rendering the view
*/
- protected void doRender(View view, Map model, RenderRequest request, RenderResponse response) throws Exception {
+ protected void doRender(View view, Map model, PortletRequest request, MimeResponse response) throws Exception {
// Expose Portlet ApplicationContext to view objects.
request.setAttribute(ViewRendererServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, getPortletApplicationContext());
@@ -1119,6 +1154,99 @@ public class DispatcherPortlet extends FrameworkPortlet {
getPortletContext().getRequestDispatcher(this.viewRendererUrl).include(request, response);
}
+
+ /**
+ * Determine an error ModelAndView via the registered HandlerExceptionResolvers.
+ * @param request current portlet request
+ * @param response current portlet response
+ * @param handler the executed handler, or null if none chosen at the time of
+ * the exception (for example, if multipart resolution failed)
+ * @param ex the exception that got thrown during handler execution
+ * @return a corresponding ModelAndView to forward to
+ * @throws Exception if no error ModelAndView found
+ */
+ protected ModelAndView processHandlerException(
+ RenderRequest request, RenderResponse response, Object handler, Exception ex)
+ throws Exception {
+
+ ModelAndView exMv = null;
+ for (Iterator it = this.handlerExceptionResolvers.iterator(); exMv == null && it.hasNext();) {
+ HandlerExceptionResolver resolver = it.next();
+ exMv = resolver.resolveException(request, response, handler, ex);
+ }
+ if (exMv != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("HandlerExceptionResolver returned ModelAndView [" + exMv + "] for exception");
+ }
+ logger.warn("Handler execution resulted in exception - forwarding to resolved error view", ex);
+ return exMv;
+ }
+ else {
+ throw ex;
+ }
+ }
+
+ /**
+ * Determine an error ModelAndView via the registered HandlerExceptionResolvers.
+ * @param request current portlet request
+ * @param response current portlet response
+ * @param handler the executed handler, or null if none chosen at the time of
+ * the exception (for example, if multipart resolution failed)
+ * @param ex the exception that got thrown during handler execution
+ * @return a corresponding ModelAndView to forward to
+ * @throws Exception if no error ModelAndView found
+ */
+ protected ModelAndView processHandlerException(
+ ResourceRequest request, ResourceResponse response, Object handler, Exception ex)
+ throws Exception {
+
+ ModelAndView exMv = null;
+ for (Iterator it = this.handlerExceptionResolvers.iterator(); exMv == null && it.hasNext();) {
+ HandlerExceptionResolver resolver = it.next();
+ exMv = resolver.resolveException(request, response, handler, ex);
+ }
+ if (exMv != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("HandlerExceptionResolver returned ModelAndView [" + exMv + "] for exception");
+ }
+ logger.warn("Handler execution resulted in exception - forwarding to resolved error view", ex);
+ return exMv;
+ }
+ else {
+ throw ex;
+ }
+ }
+
+ /**
+ * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
+ * Will just invoke afterCompletion for all interceptors whose preHandle
+ * invocation has successfully completed and returned true.
+ * @param mappedHandler the mapped HandlerExecutionChain
+ * @param interceptorIndex index of last interceptor that successfully completed
+ * @param ex Exception thrown on handler execution, or null if none
+ * @see HandlerInterceptor#afterRenderCompletion
+ */
+ private void triggerAfterActionCompletion(HandlerExecutionChain mappedHandler, int interceptorIndex,
+ ActionRequest request, ActionResponse response, Exception ex)
+ throws Exception {
+
+ // Apply afterCompletion methods of registered interceptors.
+ if (mappedHandler != null) {
+ HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
+ if (interceptors != null) {
+ for (int i = interceptorIndex; i >= 0; i--) {
+ HandlerInterceptor interceptor = interceptors[i];
+ try {
+ interceptor.afterActionCompletion(request, response, mappedHandler.getHandler(), ex);
+ }
+ catch (Throwable ex2) {
+ logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
+ }
+ }
+ }
+ }
+ }
+
/**
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
* Will just invoke afterCompletion for all interceptors whose preHandle
@@ -1149,4 +1277,64 @@ public class DispatcherPortlet extends FrameworkPortlet {
}
}
+ /**
+ * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
+ * Will just invoke afterCompletion for all interceptors whose preHandle
+ * invocation has successfully completed and returned true.
+ * @param mappedHandler the mapped HandlerExecutionChain
+ * @param interceptorIndex index of last interceptor that successfully completed
+ * @param ex Exception thrown on handler execution, or null if none
+ * @see HandlerInterceptor#afterRenderCompletion
+ */
+ private void triggerAfterResourceCompletion(HandlerExecutionChain mappedHandler, int interceptorIndex,
+ ResourceRequest request, ResourceResponse response, Exception ex)
+ throws Exception {
+
+ // Apply afterCompletion methods of registered interceptors.
+ if (mappedHandler != null) {
+ HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
+ if (interceptors != null) {
+ for (int i = interceptorIndex; i >= 0; i--) {
+ HandlerInterceptor interceptor = interceptors[i];
+ try {
+ interceptor.afterResourceCompletion(request, response, mappedHandler.getHandler(), ex);
+ }
+ catch (Throwable ex2) {
+ logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
+ * Will just invoke afterCompletion for all interceptors whose preHandle
+ * invocation has successfully completed and returned true.
+ * @param mappedHandler the mapped HandlerExecutionChain
+ * @param interceptorIndex index of last interceptor that successfully completed
+ * @param ex Exception thrown on handler execution, or null if none
+ * @see HandlerInterceptor#afterRenderCompletion
+ */
+ private void triggerAfterEventCompletion(HandlerExecutionChain mappedHandler, int interceptorIndex,
+ EventRequest request, EventResponse response, Exception ex)
+ throws Exception {
+
+ // Apply afterCompletion methods of registered interceptors.
+ if (mappedHandler != null) {
+ HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
+ if (interceptors != null) {
+ for (int i = interceptorIndex; i >= 0; i--) {
+ HandlerInterceptor interceptor = interceptors[i];
+ try {
+ interceptor.afterEventCompletion(request, response, mappedHandler.getHandler(), ex);
+ }
+ catch (Throwable ex2) {
+ logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
+ }
+ }
+ }
+ }
+ }
+
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/FrameworkPortlet.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/FrameworkPortlet.java
index 170a150ee7c3bb1e9713e62ca3a1354ae57e6114..e1822197791042ac2434b830b47f4fdd14e950eb 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/FrameworkPortlet.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/FrameworkPortlet.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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,14 +19,17 @@ package org.springframework.web.portlet;
import java.io.IOException;
import java.security.Principal;
import java.util.Map;
-
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
+import javax.portlet.EventRequest;
+import javax.portlet.EventResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
@@ -37,8 +40,14 @@ import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.SourceFilteringListener;
+import org.springframework.context.i18n.LocaleContext;
+import org.springframework.context.i18n.LocaleContextHolder;
+import org.springframework.context.i18n.SimpleLocaleContext;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.portlet.context.ConfigurablePortletApplicationContext;
import org.springframework.web.portlet.context.PortletApplicationContextUtils;
+import org.springframework.web.portlet.context.PortletRequestAttributes;
import org.springframework.web.portlet.context.PortletRequestHandledEvent;
import org.springframework.web.portlet.context.XmlPortletApplicationContext;
@@ -136,6 +145,9 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
/** Should we publish a PortletRequestHandledEvent at the end of each request? */
private boolean publishEvents = true;
+ /** Expose LocaleContext and RequestAttributes as inheritable for child threads? */
+ private boolean threadContextInheritable = false;
+
/** USER_INFO attributes that may contain the username of the current user */
private String[] userinfoUsernameAttributes = DEFAULT_USERINFO_ATTRIBUTE_NAMES;
@@ -205,13 +217,6 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
this.publishContext = publishContext;
}
- /**
- * Return whether to publish this portlet's context as a PortletContext attribute.
- */
- public boolean isPublishContext() {
- return this.publishContext;
- }
-
/**
* Set whether this portlet should publish a PortletRequestHandledEvent at the end
* of each request. Default is true; can be turned off for a slight performance
@@ -223,11 +228,19 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
}
/**
- * Return whether this portlet should publish a PortletRequestHandledEvent at the end
- * of each request.
+ * Set whether to expose the LocaleContext and RequestAttributes as inheritable
+ * for child threads (using an {@link java.lang.InheritableThreadLocal}).
+ *
Default is "false", to avoid side effects on spawned background threads.
+ * Switch this to "true" to enable inheritance for custom child threads which
+ * are spawned during request processing and only used for this request
+ * (that is, ending after their initial task, without reuse of the thread).
+ *
WARNING: Do not use inheritance for child threads if you are
+ * accessing a thread pool which is configured to potentially add new threads
+ * on demand (e.g. a JDK {@link java.util.concurrent.ThreadPoolExecutor}),
+ * since this will expose the inherited context to such a pooled thread.
*/
- public boolean isPublishEvents() {
- return this.publishEvents;
+ public void setThreadContextInheritable(boolean threadContextInheritable) {
+ this.threadContextInheritable = threadContextInheritable;
}
/**
@@ -239,15 +252,6 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
this.userinfoUsernameAttributes = userinfoUsernameAttributes;
}
- /**
- * Returns the list of attributes that will be searched in the USER_INFO map
- * when trying to find the username of the current user
- * @see #getUsernameForRequest
- */
- public String[] getUserinfoUsernameAttributes() {
- return this.userinfoUsernameAttributes;
- }
-
/**
* Overridden method of GenericPortletBean, invoked after any bean properties
@@ -297,7 +301,7 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
onRefresh(pac);
}
- if (isPublishContext()) {
+ if (this.publishContext) {
// publish the context as a portlet context attribute
String attName = getPortletContextAttributeName();
getPortletContext().setAttribute(attName, pac);
@@ -447,25 +451,39 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
}
/**
- * Delegate render requests to processRequest/doRenderService.
+ * Delegate action requests to processRequest/doActionService.
*/
@Override
- protected final void doDispatch(RenderRequest request, RenderResponse response)
+ public final void processAction(ActionRequest request, ActionResponse response)
throws PortletException, IOException {
processRequest(request, response);
}
/**
- * Delegate action requests to processRequest/doActionService.
+ * Delegate render requests to processRequest/doRenderService.
*/
@Override
- public final void processAction(ActionRequest request, ActionResponse response)
+ protected final void doDispatch(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
processRequest(request, response);
}
-
+
+ @Override
+ public void serveResource(ResourceRequest request, ResourceResponse response)
+ throws PortletException, IOException {
+
+ processRequest(request, response);
+ }
+
+ @Override
+ public void processEvent(EventRequest request, EventResponse response)
+ throws PortletException, IOException {
+
+ processRequest(request, response);
+ }
+
/**
* Process this request, publishing an event regardless of the outcome.
* The actual event handling is performed by the abstract
@@ -479,13 +497,36 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
+ // Expose current LocaleResolver and request as LocaleContext.
+ LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
+ LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable);
+
+ // Expose current RequestAttributes to current thread.
+ RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();
+ PortletRequestAttributes requestAttributes = new PortletRequestAttributes(request);
+ RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
+
+ if (logger.isTraceEnabled()) {
+ logger.trace("Bound request context to thread: " + request);
+ }
+
try {
- if (request instanceof ActionRequest) {
+ String phase = (String) request.getAttribute(PortletRequest.LIFECYCLE_PHASE);
+ if (PortletRequest.ACTION_PHASE.equals(phase)) {
doActionService((ActionRequest) request, (ActionResponse) response);
}
- else {
+ else if (PortletRequest.RENDER_PHASE.equals(phase)) {
doRenderService((RenderRequest) request, (RenderResponse) response);
}
+ else if (PortletRequest.RESOURCE_PHASE.equals(phase)) {
+ doResourceService((ResourceRequest) request, (ResourceResponse) response);
+ }
+ else if (PortletRequest.EVENT_PHASE.equals(phase)) {
+ doEventService((EventRequest) request, (EventResponse) response);
+ }
+ else {
+ throw new IllegalStateException("Invalid portlet request phase: " + phase);
+ }
}
catch (PortletException ex) {
failureCause = ex;
@@ -501,13 +542,23 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
}
finally {
+ // Reset thread-bound context.
+ RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable);
+ LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);
+
+ // Clear request attributes.
+ requestAttributes.requestCompleted();
+ if (logger.isTraceEnabled()) {
+ logger.trace("Cleared thread-bound resource request context: " + request);
+ }
+
if (failureCause != null) {
logger.error("Could not complete request", failureCause);
}
else {
logger.debug("Successfully completed request");
}
- if (isPublishEvents()) {
+ if (this.publishEvents) {
// Whether or not we succeeded, publish an event.
long processingTime = System.currentTimeMillis() - startTime;
this.portletApplicationContext.publishEvent(
@@ -520,6 +571,16 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
}
}
+ /**
+ * Build a LocaleContext for the given request, exposing the request's
+ * primary locale as current locale.
+ * @param request current HTTP request
+ * @return the corresponding LocaleContext
+ */
+ protected LocaleContext buildLocaleContext(PortletRequest request) {
+ return new SimpleLocaleContext(request.getLocale());
+ }
+
/**
* Determine the username for the given request.
*
The default implementation first tries the UserPrincipal.
@@ -560,6 +621,21 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
return null;
}
+
+ /**
+ * Subclasses must implement this method to do the work of action request handling.
+ *
The contract is essentially the same as that for the processAction
+ * method of GenericPortlet.
+ *
This class intercepts calls to ensure that exception handling and
+ * event publication takes place.
+ * @param request current action request
+ * @param response current action response
+ * @throws Exception in case of any kind of processing failure
+ * @see javax.portlet.GenericPortlet#processAction
+ */
+ protected abstract void doActionService(ActionRequest request, ActionResponse response)
+ throws Exception;
+
/**
* Subclasses must implement this method to do the work of render request handling.
*
The contract is essentially the same as that for the doDispatch
@@ -575,17 +651,31 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
throws Exception;
/**
- * Subclasses must implement this method to do the work of action request handling.
- *
The contract is essentially the same as that for the processAction
+ * Subclasses must implement this method to do the work of resource request handling.
+ *
The contract is essentially the same as that for the serveResource
* method of GenericPortlet.
*
This class intercepts calls to ensure that exception handling and
* event publication takes place.
- * @param request current action request
- * @param response current action response
+ * @param request current resource request
+ * @param response current resource response
* @throws Exception in case of any kind of processing failure
- * @see javax.portlet.GenericPortlet#processAction
+ * @see javax.portlet.GenericPortlet#serveResource
*/
- protected abstract void doActionService(ActionRequest request, ActionResponse response)
+ protected abstract void doResourceService(ResourceRequest request, ResourceResponse response)
+ throws Exception;
+
+ /**
+ * Subclasses must implement this method to do the work of event request handling.
+ *
The contract is essentially the same as that for the processEvent
+ * method of GenericPortlet.
+ *
This class intercepts calls to ensure that exception handling and
+ * event publication takes place.
+ * @param request current event request
+ * @param response current event response
+ * @throws Exception in case of any kind of processing failure
+ * @see javax.portlet.GenericPortlet#processEvent
+ */
+ protected abstract void doEventService(EventRequest request, EventResponse response)
throws Exception;
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/HandlerAdapter.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/HandlerAdapter.java
index ef771e02c372bc15a000c7db200135a862662559..c1e618fa6d4fcfcdbc67d5c9eae89baf0e0505d8 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/HandlerAdapter.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/HandlerAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2006 the original author or authors.
+ * Copyright 2002-2009 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,8 +18,12 @@ package org.springframework.web.portlet;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
+import javax.portlet.EventRequest;
+import javax.portlet.EventResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
/**
* Portlet MVC framework SPI interface, allowing parameterization of core MVC workflow.
@@ -67,6 +71,7 @@ public interface HandlerAdapter {
* to the supports method of this interface, which must have
* returned true.
* @throws Exception in case of errors
+ * @see javax.portlet.Portlet#processAction
*/
void handleAction(ActionRequest request, ActionResponse response, Object handler) throws Exception;
@@ -81,7 +86,36 @@ public interface HandlerAdapter {
* @throws Exception in case of errors
* @return ModelAndView object with the name of the view and the required
* model data, or null if the request has been handled directly
+ * @see javax.portlet.Portlet#render
*/
ModelAndView handleRender(RenderRequest request, RenderResponse response, Object handler) throws Exception;
+ /**
+ * Use the given handler to handle this resource request.
+ * The workflow that is required may vary widely.
+ * @param request current render request
+ * @param response current render response
+ * @param handler handler to use. This object must have previously been passed
+ * to the supports method of this interface, which must have
+ * returned true.
+ * @throws Exception in case of errors
+ * @return ModelAndView object with the name of the view and the required
+ * model data, or null if the request has been handled directly
+ * @see javax.portlet.ResourceServingPortlet#serveResource
+ */
+ ModelAndView handleResource(ResourceRequest request, ResourceResponse response, Object handler) throws Exception;
+
+ /**
+ * Use the given handler to handle this event request.
+ * The workflow that is required may vary widely.
+ * @param request current action request
+ * @param response current action response
+ * @param handler handler to use. This object must have previously been passed
+ * to the supports method of this interface, which must have
+ * returned true.
+ * @throws Exception in case of errors
+ * @see javax.portlet.EventPortlet#processEvent
+ */
+ void handleEvent(EventRequest request, EventResponse response, Object handler) throws Exception;
+
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/HandlerExceptionResolver.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/HandlerExceptionResolver.java
index 42695edd47489e919428d58d8e635d2e8bd22b7c..d2efc4484dd28c0f3a7ba389d7aac7ca3f11db31 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/HandlerExceptionResolver.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/HandlerExceptionResolver.java
@@ -1,12 +1,12 @@
/*
- * Copyright 2002-2005 the original author or authors.
- *
+ * Copyright 2002-2009 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.
@@ -18,6 +18,8 @@ package org.springframework.web.portlet;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
/**
* Interface to be implemented by objects than can resolve exceptions thrown
@@ -47,4 +49,17 @@ public interface HandlerExceptionResolver {
ModelAndView resolveException(
RenderRequest request, RenderResponse response, Object handler, Exception ex);
+ /**
+ * Try to resolve the given exception that got thrown during on handler execution,
+ * returning a ModelAndView that represents a specific error page if appropriate.
+ * @param request current portlet request
+ * @param response current portlet response
+ * @param handler the executed handler, or null if none chosen at the time of
+ * the exception (for example, if multipart resolution failed)
+ * @param ex the exception that got thrown during handler execution
+ * @return a corresponding ModelAndView to forward to, or null for default processing
+ */
+ ModelAndView resolveException(
+ ResourceRequest request, ResourceResponse response, Object handler, Exception ex);
+
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/HandlerInterceptor.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/HandlerInterceptor.java
index 9ab888cd4c3b18e0261395ebd6e3b5a85768434c..a09d13d5b707f06a91b7044e61032742c185862f 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/HandlerInterceptor.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/HandlerInterceptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2007 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -20,6 +20,10 @@ import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
+import javax.portlet.EventResponse;
+import javax.portlet.EventRequest;
+import javax.portlet.ResourceResponse;
+import javax.portlet.ResourceRequest;
/**
* Workflow interface that allows for customized handler execution chains.
@@ -130,7 +134,7 @@ public interface HandlerInterceptor {
* @throws Exception in case of errors
*/
boolean preHandleAction(ActionRequest request, ActionResponse response, Object handler)
- throws Exception;
+ throws Exception;
/**
* Callback after completion of request processing in the action phase, that is,
@@ -149,7 +153,7 @@ public interface HandlerInterceptor {
*/
void afterActionCompletion(
ActionRequest request, ActionResponse response, Object handler, Exception ex)
- throws Exception;
+ throws Exception;
/**
* Intercept the execution of a handler in the render phase.
@@ -169,7 +173,7 @@ public interface HandlerInterceptor {
* @throws Exception in case of errors
*/
boolean preHandleRender(RenderRequest request, RenderResponse response, Object handler)
- throws Exception;
+ throws Exception;
/**
* Intercept the execution of a handler in the render phase.
@@ -208,4 +212,101 @@ public interface HandlerInterceptor {
RenderRequest request, RenderResponse response, Object handler, Exception ex)
throws Exception;
+ /**
+ * Intercept the execution of a handler in the render phase.
+ *
Called after a HandlerMapping determines an appropriate handler object
+ * to handle a {@link RenderRequest}, but before said HandlerAdapter actually
+ * invokes the handler.
+ *
{@link DispatcherPortlet} processes a handler in an execution chain,
+ * consisting of any number of interceptors, with the handler itself at the end.
+ * With this method, each interceptor can decide to abort the execution chain,
+ * typically throwing an exception or writing a custom response.
+ * @param request current portlet render request
+ * @param response current portlet render response
+ * @param handler chosen handler to execute, for type and/or instance evaluation
+ * @return true if the execution chain should proceed with the
+ * next interceptor or the handler itself. Else, DispatcherPortlet
+ * assumes that this interceptor has already dealt with the response itself
+ * @throws Exception in case of errors
+ */
+ boolean preHandleResource(ResourceRequest request, ResourceResponse response, Object handler)
+ throws Exception;
+
+ /**
+ * Intercept the execution of a handler in the render phase.
+ *
Called after a {@link HandlerAdapter} actually invoked the handler, but
+ * before the DispatcherPortlet renders the view. Can thus expose
+ * additional model objects to the view via the given {@link ModelAndView}.
+ *
DispatcherPortlet processes a handler in an execution chain,
+ * consisting of any number of interceptors, with the handler itself at the end.
+ * With this method, each interceptor can post-process an execution, getting
+ * applied in inverse order of the execution chain.
+ * @param request current portlet render request
+ * @param response current portlet render response
+ * @param handler chosen handler to execute, for type and/or instance examination
+ * @param modelAndView the ModelAndView that the handler returned
+ * (can also be null)
+ * @throws Exception in case of errors
+ */
+ void postHandleResource(
+ ResourceRequest request, ResourceResponse response, Object handler, ModelAndView modelAndView)
+ throws Exception;
+
+ /**
+ * Callback after completion of request processing, that is, after rendering
+ * the view. Will be called on any outcome of handler execution, thus allowing
+ * for proper resource cleanup.
+ *
Note: Will only be called if this interceptor's
+ * {@link #preHandleRender(javax.portlet.RenderRequest, javax.portlet.RenderResponse, Object)}
+ * method has successfully completed and returned true!
+ * @param request current portlet render request
+ * @param response current portlet render response
+ * @param handler chosen handler to execute, for type and/or instance examination
+ * @param ex exception thrown on handler execution, if any
+ * @throws Exception in case of errors
+ */
+ void afterResourceCompletion(
+ ResourceRequest request, ResourceResponse response, Object handler, Exception ex)
+ throws Exception;
+
+
+ /**
+ * Intercept the execution of a handler in the action phase.
+ *
Called after a HandlerMapping determines an appropriate handler object
+ * to handle an {@link ActionRequest}, but before said HandlerAdapter actually
+ * invokes the handler.
+ *
{@link DispatcherPortlet} processes a handler in an execution chain,
+ * consisting of any number of interceptors, with the handler itself at the end.
+ * With this method, each interceptor can decide to abort the execution chain,
+ * typically throwing an exception or writing a custom response.
+ * @param request current portlet action request
+ * @param response current portlet action response
+ * @param handler chosen handler to execute, for type and/or instance evaluation
+ * @return true if the execution chain should proceed with the
+ * next interceptor or the handler itself. Else, DispatcherPortlet
+ * assumes that this interceptor has already dealt with the response itself
+ * @throws Exception in case of errors
+ */
+ boolean preHandleEvent(EventRequest request, EventResponse response, Object handler)
+ throws Exception;
+
+ /**
+ * Callback after completion of request processing in the action phase, that is,
+ * after rendering the view. Will be called on any outcome of handler execution,
+ * thus allowing for proper resource cleanup.
+ *
Note: Will only be called if this interceptor's
+ * {@link #preHandleAction(javax.portlet.ActionRequest, javax.portlet.ActionResponse, Object)}
+ * method has successfully completed and returned true!
+ * @param request current portlet action request
+ * @param response current portlet action response
+ * @param handler chosen handler to execute, for type and/or instance examination
+ * @param ex exception thrown on handler execution, if any (only included as
+ * additional context information for the case where a handler threw an exception;
+ * request execution may have failed even when this argument is null)
+ * @throws Exception in case of errors
+ */
+ void afterEventCompletion(
+ EventRequest request, EventResponse response, Object handler, Exception ex)
+ throws Exception;
+
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ActionMapping.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ActionMapping.java
new file mode 100644
index 0000000000000000000000000000000000000000..0adb5ded1c673708bed723b861987874fe9272c1
--- /dev/null
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ActionMapping.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2002-2009 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.web.portlet.bind.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.web.bind.annotation.Mapping;
+
+/**
+ * Annotation for mapping Portlet action requests onto handler methods.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ * @see org.springframework.web.bind.annotation.RequestMapping
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Mapping
+public @interface ActionMapping {
+
+ /**
+ * The name of the action, according to the Portlet 2.0
+ * "javax.portlet.action" parameter.
+ *
If not specified, the method will be used as default handler:
+ * i.e. for action requests where no specific action mapping was found.
+ *
Note that all such annotated action methods only apply within the
+ * @RequestMapping constraints of the containing handler class.
+ * @see javax.portlet.ActionRequest#ACTION_NAME
+ */
+ String value() default "";
+
+ /**
+ * The parameters of the mapped request, narrowing the primary mapping.
+ *
Same format for any environment: a sequence of "myParam=myValue" style
+ * expressions, with a request only mapped if each such parameter is found
+ * to have the given value. "myParam" style expressions are also supported,
+ * with such parameters having to be present in the request (allowed to have
+ * any value). Finally, "!myParam" style expressions indicate that the
+ * specified parameter is not supposed to be present in the request.
+ * @see org.springframework.web.bind.annotation.RequestMapping#params()
+ */
+ String[] params() default {};
+
+}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/EventMapping.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/EventMapping.java
new file mode 100644
index 0000000000000000000000000000000000000000..cbd3086d66227db74d8ba42adc7f981e97da85cf
--- /dev/null
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/EventMapping.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2002-2009 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.web.portlet.bind.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.web.bind.annotation.Mapping;
+
+/**
+ * Annotation for mapping Portlet event requests onto handler methods.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ * @see org.springframework.web.bind.annotation.RequestMapping
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Mapping
+public @interface EventMapping {
+
+ /**
+ * The name of the event to be handled.
+ *
Typically the local name of the event, but fully qualified names
+ * with a "{...}" namespace part will be mapped correctly as well.
+ *
If not specified, the render method will be invoked for any
+ * event request within its general mapping.
+ * @see javax.portlet.EventRequest#getEvent()
+ * @see javax.portlet.Event#getName()
+ */
+ String value();
+
+ /**
+ * The parameters of the mapped request, narrowing the primary mapping.
+ *
Same format for any environment: a sequence of "myParam=myValue" style
+ * expressions, with a request only mapped if each such parameter is found
+ * to have the given value. "myParam" style expressions are also supported,
+ * with such parameters having to be present in the request (allowed to have
+ * any value). Finally, "!myParam" style expressions indicate that the
+ * specified parameter is not supposed to be present in the request.
+ * @see org.springframework.web.bind.annotation.RequestMapping#params()
+ */
+ String[] params() default {};
+
+}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/RenderMapping.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/RenderMapping.java
new file mode 100644
index 0000000000000000000000000000000000000000..7eb8b1dcf9d547e5491e42162f9b0eb4de5b85f2
--- /dev/null
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/RenderMapping.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2002-2009 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.web.portlet.bind.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.web.bind.annotation.Mapping;
+
+/**
+ * Annotation for mapping Portlet render requests onto handler methods.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ * @see org.springframework.web.bind.annotation.RequestMapping
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Mapping
+public @interface RenderMapping {
+
+ /**
+ * The window state that the annotated render method applies for.
+ *
If not specified, the render method will be invoked for any
+ * window state within its general mapping.
+ *
Standard Portlet spec values: "NORMAL", "MAXIMIZED", "MINIMIZED".
+ * Custom window states can be used as well, as supported by the portal.
+ * @see javax.portlet.PortletRequest#getWindowState()
+ */
+ String value() default "";
+
+ /**
+ * The parameters of the mapped request, narrowing the primary mapping.
+ *
Same format for any environment: a sequence of "myParam=myValue" style
+ * expressions, with a request only mapped if each such parameter is found
+ * to have the given value. "myParam" style expressions are also supported,
+ * with such parameters having to be present in the request (allowed to have
+ * any value). Finally, "!myParam" style expressions indicate that the
+ * specified parameter is not supposed to be present in the request.
+ * @see org.springframework.web.bind.annotation.RequestMapping#params()
+ */
+ String[] params() default {};
+
+}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ResourceMapping.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ResourceMapping.java
new file mode 100644
index 0000000000000000000000000000000000000000..de9ac2836fc8ac7ac9929279c852bc1d113fc109
--- /dev/null
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ResourceMapping.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2002-2009 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.web.portlet.bind.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.web.bind.annotation.Mapping;
+
+/**
+ * Annotation for mapping Portlet resource requests onto handler methods.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ * @see org.springframework.web.bind.annotation.RequestMapping
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Mapping
+public @interface ResourceMapping {
+
+ /**
+ * The id of the resource to be handled.
+ *
If not specified, the render method will be invoked for any
+ * resource request within its general mapping.
+ * @see javax.portlet.ResourceRequest#getResourceID()
+ */
+ String value() default "";
+
+ /**
+ * The parameters of the mapped request, narrowing the primary mapping.
+ *
Same format for any environment: a sequence of "myParam=myValue" style
+ * expressions, with a request only mapped if each such parameter is found
+ * to have the given value. "myParam" style expressions are also supported,
+ * with such parameters having to be present in the request (allowed to have
+ * any value). Finally, "!myParam" style expressions indicate that the
+ * specified parameter is not supposed to be present in the request.
+ * @see org.springframework.web.bind.annotation.RequestMapping#params()
+ */
+ String[] params() default {};
+
+}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/package.html b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/package.html
new file mode 100644
index 0000000000000000000000000000000000000000..943baab59fc420090563413d06112381a57f9758
--- /dev/null
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/package.html
@@ -0,0 +1,7 @@
+
+
+
+Annotations for binding portlet requests to handler methods.
+
+
+
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/AbstractMapBasedHandlerMapping.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/AbstractMapBasedHandlerMapping.java
index e9479b5ecc9743ca92364ab6c984420afb1b68dd..14174097f9db68285f55858d91022d504557ce06 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/AbstractMapBasedHandlerMapping.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/AbstractMapBasedHandlerMapping.java
@@ -22,6 +22,7 @@ import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import org.springframework.beans.BeansException;
@@ -80,6 +81,7 @@ public abstract class AbstractMapBasedHandlerMapping extends AbstractHandlerM
Collections.sort(predicates);
for (PortletRequestMappingPredicate predicate : predicates) {
if (predicate.match(request)) {
+ predicate.validate(request);
return predicateMap.get(predicate);
}
}
@@ -187,6 +189,13 @@ public abstract class AbstractMapBasedHandlerMapping extends AbstractHandlerM
* @param request current portlet request
*/
boolean match(PortletRequest request);
+
+ /**
+ * Validate this predicate's mapping against the current request.
+ * @param request current portlet request
+ * @throws PortletException if validation failed
+ */
+ void validate(PortletRequest request) throws PortletException;
}
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/HandlerInterceptorAdapter.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/HandlerInterceptorAdapter.java
index 5a3557be7436b785df4bcbf81512dcda3b88ae9e..4920da4f68cce5149fe37595e32127732e0e1d11 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/HandlerInterceptorAdapter.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/HandlerInterceptorAdapter.java
@@ -1,12 +1,12 @@
/*
- * Copyright 2002-2005 the original author or authors.
- *
+ * Copyright 2002-2009 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.
@@ -16,21 +16,22 @@
package org.springframework.web.portlet.handler;
-import java.io.IOException;
-
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
-import javax.portlet.RenderRequest;
-import javax.portlet.RenderResponse;
+import javax.portlet.EventRequest;
+import javax.portlet.EventResponse;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
-import javax.portlet.PortletException;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
import org.springframework.web.portlet.HandlerInterceptor;
import org.springframework.web.portlet.ModelAndView;
/**
- * Abstract adapter class for the HandlerInterceptor interface,
+ * Abstract adapter class for the {@link HandlerInterceptor} interface,
* for simplified implementation of pre-only/post-only interceptors.
*
* @author Juergen Hoeller
@@ -40,29 +41,31 @@ import org.springframework.web.portlet.ModelAndView;
public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {
/**
- * This implementation delegates to preHandle.
- * @see #preHandle
+ * This implementation delegates to {@link #preHandle}.
*/
- public boolean preHandleAction(ActionRequest request, ActionResponse response, Object handler) throws Exception {
+ public boolean preHandleAction(ActionRequest request, ActionResponse response, Object handler)
+ throws Exception {
+
return preHandle(request, response, handler);
}
/**
- * This implementation delegates to afterCompletion.
- * @see #afterCompletion
+ * This implementation delegates to {@link #afterCompletion}.
*/
public void afterActionCompletion(
- ActionRequest request, ActionResponse response, Object handler, Exception ex) throws Exception {
+ ActionRequest request, ActionResponse response, Object handler, Exception ex)
+ throws Exception {
afterCompletion(request, response, handler, ex);
}
/**
- * This implementation delegates to preHandle.
- * @see #preHandle
+ * This implementation delegates to {@link #preHandle}.
*/
- public boolean preHandleRender(RenderRequest request, RenderResponse response, Object handler) throws Exception {
+ public boolean preHandleRender(RenderRequest request, RenderResponse response, Object handler)
+ throws Exception {
+
return preHandle(request, response, handler);
}
@@ -70,26 +73,72 @@ public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {
* This implementation is empty.
*/
public void postHandleRender(
- RenderRequest request, RenderResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+ RenderRequest request, RenderResponse response, Object handler, ModelAndView modelAndView)
+ throws Exception {
}
/**
- * This implementation delegates to afterCompletion.
- * @see #afterCompletion
+ * This implementation delegates to {@link #afterCompletion}.
*/
public void afterRenderCompletion(
- RenderRequest request, RenderResponse response, Object handler, Exception ex) throws Exception {
+ RenderRequest request, RenderResponse response, Object handler, Exception ex)
+ throws Exception {
+
+ afterCompletion(request, response, handler, ex);
+ }
+
+
+ /**
+ * This implementation delegates to {@link #preHandle}.
+ */
+ public boolean preHandleResource(ResourceRequest request, ResourceResponse response, Object handler)
+ throws Exception {
+
+ return preHandle(request, response, handler);
+ }
+
+ /**
+ * This implementation is empty.
+ */
+ public void postHandleResource(
+ ResourceRequest request, ResourceResponse response, Object handler, ModelAndView modelAndView)
+ throws Exception {
+ }
+
+ /**
+ * This implementation delegates to {@link #afterCompletion}.
+ */
+ public void afterResourceCompletion(
+ ResourceRequest request, ResourceResponse response, Object handler, Exception ex)
+ throws Exception {
+
+ afterCompletion(request, response, handler, ex);
+ }
+
+
+ /**
+ * This implementation delegates to {@link #preHandle}.
+ */
+ public boolean preHandleEvent(EventRequest request, EventResponse response, Object handler)
+ throws Exception {
+
+ return preHandle(request, response, handler);
+ }
+
+ /**
+ * This implementation delegates to {@link #afterCompletion}.
+ */
+ public void afterEventCompletion(
+ EventRequest request, EventResponse response, Object handler, Exception ex)
+ throws Exception {
afterCompletion(request, response, handler, ex);
}
/**
- * Default callback that both preHandleRender
- * and preHandleAction delegate to.
+ * Default callback that all "pre*" methods delegate to.
*
This implementation always returns true.
- * @see #preHandleRender
- * @see #preHandleAction
*/
protected boolean preHandle(PortletRequest request, PortletResponse response, Object handler)
throws Exception {
@@ -98,14 +147,12 @@ public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {
}
/**
- * Default callback that both preHandleRender
- * and preHandleAction delegate to.
+ * Default callback that all "after*" methods delegate to.
*
This implementation is empty.
- * @see #afterRenderCompletion
- * @see #afterActionCompletion
*/
protected void afterCompletion(
- PortletRequest request, PortletResponse response, Object handler, Exception ex) throws Exception {
+ PortletRequest request, PortletResponse response, Object handler, Exception ex)
+ throws Exception {
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/PortletContentGenerator.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/PortletContentGenerator.java
index 470e0e2aa093c7677c0a956bee1e8e028191fe65..318c5d1ceb65deecbfbfc810ed6b911748177ea5 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/PortletContentGenerator.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/PortletContentGenerator.java
@@ -16,11 +16,10 @@
package org.springframework.web.portlet.handler;
+import javax.portlet.MimeResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
-import javax.portlet.RenderRequest;
-import javax.portlet.RenderResponse;
import org.springframework.web.portlet.context.PortletApplicationObjectSupport;
@@ -102,7 +101,7 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu
* @param response current portlet response
* @throws PortletException if the request cannot be handled because a check failed
*/
- protected final void checkAndPrepare(RenderRequest request, RenderResponse response)
+ protected final void checkAndPrepare(PortletRequest request, MimeResponse response)
throws PortletException {
checkAndPrepare(request, response, this.cacheSeconds);
@@ -118,8 +117,7 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu
* response should be cacheable for, 0 to prevent caching
* @throws PortletException if the request cannot be handled because a check failed
*/
- protected final void checkAndPrepare(
- RenderRequest request, RenderResponse response, int cacheSeconds)
+ protected final void checkAndPrepare(PortletRequest request, MimeResponse response, int cacheSeconds)
throws PortletException {
check(request, response);
@@ -129,7 +127,7 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu
/**
* Prevent the render response from being cached.
*/
- protected final void preventCaching(RenderResponse response) {
+ protected final void preventCaching(MimeResponse response) {
cacheForSeconds(response, 0);
}
@@ -139,8 +137,8 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu
* @param seconds number of seconds into the future that the response
* should be cacheable for
*/
- protected final void cacheForSeconds(RenderResponse response, int seconds) {
- response.setProperty(RenderResponse.EXPIRATION_CACHE, Integer.toString(seconds));
+ protected final void cacheForSeconds(MimeResponse response, int seconds) {
+ response.setProperty(MimeResponse.EXPIRATION_CACHE, Integer.toString(seconds));
}
/**
@@ -149,7 +147,7 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu
* @param seconds positive number of seconds into the future that the
* response should be cacheable for, 0 to prevent caching
*/
- protected final void applyCacheSeconds(RenderResponse response, int seconds) {
+ protected final void applyCacheSeconds(MimeResponse response, int seconds) {
if (seconds > 0) {
cacheForSeconds(response, seconds);
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/PortletRequestMethodNotSupportedException.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/PortletRequestMethodNotSupportedException.java
new file mode 100644
index 0000000000000000000000000000000000000000..f347a027fba4e32d5d53579210eeccca32ec3d3d
--- /dev/null
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/PortletRequestMethodNotSupportedException.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2002-2009 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.web.portlet.handler;
+
+import javax.portlet.PortletException;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * Exception thrown when a request handler does not support a
+ * specific request method.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class PortletRequestMethodNotSupportedException extends PortletException {
+
+ private String method;
+
+ private String[] supportedMethods;
+
+
+ /**
+ * Create a new PortletRequestMethodNotSupportedException.
+ * @param method the unsupported HTTP request method
+ */
+ public PortletRequestMethodNotSupportedException(String method) {
+ this(method, null);
+ }
+
+ /**
+ * Create a new PortletRequestMethodNotSupportedException.
+ * @param method the unsupported HTTP request method
+ * @param supportedMethods the actually supported HTTP methods
+ */
+ public PortletRequestMethodNotSupportedException(String method, String[] supportedMethods) {
+ super("Request method '" + method + "' not supported by mapped handler");
+ this.method = method;
+ this.supportedMethods = supportedMethods;
+ }
+
+ /**
+ * Create a new PortletRequestMethodNotSupportedException.
+ * @param method the unsupported HTTP request method
+ * @param supportedMethods the actually supported HTTP methods
+ */
+ public PortletRequestMethodNotSupportedException(String[] supportedMethods) {
+ super("Mapped handler only supports client data requests with methods " +
+ StringUtils.arrayToCommaDelimitedString(supportedMethods));
+ this.supportedMethods = supportedMethods;
+ }
+
+
+ /**
+ * Return the HTTP request method that caused the failure.
+ */
+ public String getMethod() {
+ return this.method;
+ }
+
+ /**
+ * Return the actually supported HTTP methods, if known.
+ */
+ public String[] getSupportedMethods() {
+ return this.supportedMethods;
+ }
+
+}
\ No newline at end of file
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/SimpleMappingExceptionResolver.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/SimpleMappingExceptionResolver.java
index 03071d1419becc13e075a2534f779da8f661f735..9bb2f51b6787df8f8494d6d1f9fcc4b5174279a3 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/SimpleMappingExceptionResolver.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/SimpleMappingExceptionResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2007 the original author or authors.
+ * Copyright 2002-2008 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,9 +19,12 @@ package org.springframework.web.portlet.handler;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Set;
-
+import javax.portlet.MimeResponse;
+import javax.portlet.PortletRequest;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
import javax.portlet.WindowState;
import org.apache.commons.logging.Log;
@@ -190,6 +193,18 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
}
}
+ public ModelAndView resolveException(
+ ResourceRequest request, ResourceResponse response, Object handler, Exception ex) {
+
+ if (shouldApplyTo(request, handler)) {
+ return doResolveException(request, response, handler, ex);
+ }
+ else {
+ return null;
+ }
+ }
+
+
/**
* Check whether this resolver is supposed to apply to the given handler.
*
The default implementation checks against the specified mapped handlers
@@ -203,19 +218,19 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
* @see #setMappedHandlers
* @see #setMappedHandlerClasses
*/
- protected boolean shouldApplyTo(RenderRequest request, Object handler) {
+ protected boolean shouldApplyTo(PortletRequest request, Object handler) {
// If the portlet is minimized and we don't want to render then return null.
if (WindowState.MINIMIZED.equals(request.getWindowState()) && !this.renderWhenMinimized) {
return false;
}
-
+ // Check mapped handlers...
if (handler != null) {
if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) {
return true;
}
if (this.mappedHandlerClasses != null) {
- for (int i = 0; i < this.mappedHandlerClasses.length; i++) {
- if (this.mappedHandlerClasses[i].isInstance(handler)) {
+ for (Class mappedClass : this.mappedHandlerClasses) {
+ if (mappedClass.isInstance(handler)) {
return true;
}
}
@@ -236,7 +251,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
* @return a corresponding ModelAndView to forward to, or null for default processing
*/
protected ModelAndView doResolveException(
- RenderRequest request, RenderResponse response, Object handler, Exception ex) {
+ PortletRequest request, MimeResponse response, Object handler, Exception ex) {
// Log exception, both at debug log level and at warn level, if desired.
if (logger.isDebugEnabled()) {
@@ -266,7 +281,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
* @see #buildLogMessage
* @see org.apache.commons.logging.Log#warn(Object, Throwable)
*/
- protected void logException(Exception ex, RenderRequest request) {
+ protected void logException(Exception ex, PortletRequest request) {
if (this.warnLogger != null && this.warnLogger.isWarnEnabled()) {
this.warnLogger.warn(buildLogMessage(ex, request), ex);
}
@@ -279,7 +294,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
* @param request current portlet request (useful for obtaining metadata)
* @return the log message to use
*/
- protected String buildLogMessage(Exception ex, RenderRequest request) {
+ protected String buildLogMessage(Exception ex, PortletRequest request) {
return "Handler execution resulted in exception";
}
@@ -292,7 +307,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
* @param request current portlet request (useful for obtaining metadata)
* @return the resolved view name, or null if none found
*/
- protected String determineViewName(Exception ex, RenderRequest request) {
+ protected String determineViewName(Exception ex, PortletRequest request) {
String viewName = null;
// Check for specific exception mappings.
if (this.exceptionMappings != null) {
@@ -348,7 +363,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
}
private int getDepth(String exceptionMapping, Class exceptionClass, int depth) {
- if (exceptionClass.getName().indexOf(exceptionMapping) != -1) {
+ if (exceptionClass.getName().contains(exceptionMapping)) {
// Found it!
return depth;
}
@@ -369,7 +384,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
* @return the ModelAndView instance
* @see #getModelAndView(String, Exception)
*/
- protected ModelAndView getModelAndView(String viewName, Exception ex, RenderRequest request) {
+ protected ModelAndView getModelAndView(String viewName, Exception ex, PortletRequest request) {
return getModelAndView(viewName, ex);
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/SimplePortletHandlerAdapter.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/SimplePortletHandlerAdapter.java
index f2f2ad3142b4a60cd6c9970896fc6e274f3b1a95..a4ea17611da45238ff0c07b438da226883f9edcb 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/SimplePortletHandlerAdapter.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/SimplePortletHandlerAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2006 the original author or authors.
+ * Copyright 2002-2008 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,12 +18,21 @@ package org.springframework.web.portlet.handler;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
+import javax.portlet.EventPortlet;
+import javax.portlet.EventRequest;
+import javax.portlet.EventResponse;
import javax.portlet.Portlet;
+import javax.portlet.PortletContext;
+import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
+import javax.portlet.ResourceServingPortlet;
import org.springframework.web.portlet.HandlerAdapter;
import org.springframework.web.portlet.ModelAndView;
+import org.springframework.web.portlet.context.PortletContextAware;
/**
* Adapter to use the Portlet interface with the generic DispatcherPortlet.
@@ -49,8 +58,16 @@ import org.springframework.web.portlet.ModelAndView;
* @see SimplePortletPostProcessor
* @see org.springframework.web.portlet.mvc.PortletWrappingController
*/
-public class SimplePortletHandlerAdapter implements HandlerAdapter {
+public class SimplePortletHandlerAdapter implements HandlerAdapter, PortletContextAware {
+ private PortletContext portletContext;
+
+
+ public void setPortletContext(PortletContext portletContext) {
+ this.portletContext = portletContext;
+ }
+
+
public boolean supports(Object handler) {
return (handler instanceof Portlet);
}
@@ -68,4 +85,32 @@ public class SimplePortletHandlerAdapter implements HandlerAdapter {
return null;
}
+ public ModelAndView handleResource(ResourceRequest request, ResourceResponse response, Object handler)
+ throws Exception {
+
+ if (handler instanceof ResourceServingPortlet) {
+ ((ResourceServingPortlet) handler).serveResource(request, response);
+ }
+ else {
+ // equivalent to Portlet 2.0 GenericPortlet
+ if (request.getResourceID() != null) {
+ PortletRequestDispatcher rd = this.portletContext.getRequestDispatcher(request.getResourceID());
+ if (rd != null) {
+ rd.forward(request, response);
+ }
+ }
+ }
+ return null;
+ }
+
+ public void handleEvent(EventRequest request, EventResponse response, Object handler) throws Exception {
+ if (handler instanceof EventPortlet) {
+ ((EventPortlet) handler).processEvent(request, response);
+ }
+ else {
+ // if no event processing method was found just keep render params
+ response.setRenderParameters(request);
+ }
+ }
+
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/SimplePortletPostProcessor.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/SimplePortletPostProcessor.java
index 6525db44aee7b395fd5a8c40ab4c83a2954734c0..b5687fd6e7657d45dda1f7d278efc23fec7c22b4 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/SimplePortletPostProcessor.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/SimplePortletPostProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2006 the original author or authors.
+ * Copyright 2002-2008 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,13 +18,16 @@ package org.springframework.web.portlet.handler;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashSet;
import java.util.Locale;
+import java.util.Map;
import java.util.ResourceBundle;
-
import javax.portlet.Portlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
@@ -144,23 +147,47 @@ public class SimplePortletPostProcessor
}
public String getPortletName() {
- return portletName;
+ return this.portletName;
}
public PortletContext getPortletContext() {
- return portletContext;
+ return this.portletContext;
}
public String getInitParameter(String paramName) {
return null;
}
- public Enumeration getInitParameterNames() {
- return Collections.enumeration(Collections.EMPTY_SET);
+ public Enumeration getInitParameterNames() {
+ return Collections.enumeration(new HashSet());
}
public ResourceBundle getResourceBundle(Locale locale) {
- return portletConfig == null ? null : portletConfig.getResourceBundle(locale);
+ return (this.portletConfig != null ? this.portletConfig.getResourceBundle(locale) : null);
+ }
+
+ public Enumeration getPublicRenderParameterNames() {
+ return Collections.enumeration(new HashSet());
+ }
+
+ public String getDefaultNamespace() {
+ return XMLConstants.NULL_NS_URI;
+ }
+
+ public Enumeration getPublishingEventQNames() {
+ return Collections.enumeration(new HashSet());
+ }
+
+ public Enumeration getProcessingEventQNames() {
+ return Collections.enumeration(new HashSet());
+ }
+
+ public Enumeration getSupportedLocales() {
+ return Collections.enumeration(new HashSet());
+ }
+
+ public Map getContainerRuntimeOptions() {
+ return (this.portletConfig != null ? this.portletConfig.getContainerRuntimeOptions() : null);
}
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/UserRoleAuthorizationInterceptor.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/UserRoleAuthorizationInterceptor.java
index 14c9f7a63f63d18182c45c6f11f929bd7a46747f..57f4119b6423925156339f415a6bf22dbeb7f20c 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/UserRoleAuthorizationInterceptor.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/UserRoleAuthorizationInterceptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2006 the original author or authors.
+ * Copyright 2002-2008 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.
@@ -51,8 +51,8 @@ public class UserRoleAuthorizationInterceptor extends HandlerInterceptorAdapter
throws PortletException, IOException {
if (this.authorizedRoles != null) {
- for (int i = 0; i < this.authorizedRoles.length; i++) {
- if (request.isUserInRole(this.authorizedRoles[i])) {
+ for (String role : this.authorizedRoles) {
+ if (request.isUserInRole(role)) {
return true;
}
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/WebRequestHandlerInterceptorAdapter.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/WebRequestHandlerInterceptorAdapter.java
index 9389feabe44d25f2f8fcf53ae2122d76d2f19f1a..a29cd0578ec2ebf3f94921a601b6b608177b0b38 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/WebRequestHandlerInterceptorAdapter.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/WebRequestHandlerInterceptorAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2006 the original author or authors.
+ * Copyright 2002-2008 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,8 +18,12 @@ package org.springframework.web.portlet.handler;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
+import javax.portlet.EventRequest;
+import javax.portlet.EventResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
import org.springframework.util.Assert;
import org.springframework.web.context.request.WebRequestInterceptor;
@@ -105,4 +109,35 @@ public class WebRequestHandlerInterceptorAdapter implements HandlerInterceptor {
this.requestInterceptor.afterCompletion(new PortletWebRequest(request), ex);
}
+ public boolean preHandleResource(ResourceRequest request, ResourceResponse response, Object handler)
+ throws Exception {
+
+ this.requestInterceptor.preHandle(new PortletWebRequest(request));
+ return true;
+ }
+
+ public void postHandleResource(ResourceRequest request, ResourceResponse response, Object handler, ModelAndView modelAndView)
+ throws Exception {
+
+ this.requestInterceptor.postHandle(new PortletWebRequest(request),
+ (modelAndView != null ? modelAndView.getModelMap() : null));
+ }
+
+ public void afterResourceCompletion(ResourceRequest request, ResourceResponse response, Object handler,
+ Exception ex) throws Exception {
+
+ this.requestInterceptor.afterCompletion(new PortletWebRequest(request), ex);
+ }
+
+ public boolean preHandleEvent(EventRequest request, EventResponse response, Object handler) throws Exception {
+ this.requestInterceptor.preHandle(new PortletWebRequest(request));
+ return true;
+ }
+
+ public void afterEventCompletion(EventRequest request, EventResponse response, Object handler, Exception ex)
+ throws Exception {
+
+ this.requestInterceptor.afterCompletion(new PortletWebRequest(request), ex);
+ }
+
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/multipart/DefaultMultipartActionRequest.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/multipart/DefaultMultipartActionRequest.java
index 01b46e47f2f574fb0414d15a21e74333466831ff..a1de7c049b3154f27146b1a361ee95846edb51bf 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/multipart/DefaultMultipartActionRequest.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/multipart/DefaultMultipartActionRequest.java
@@ -24,9 +24,9 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.portlet.ActionRequest;
+import javax.portlet.filter.ActionRequestWrapper;
import org.springframework.web.multipart.MultipartFile;
-import org.springframework.web.portlet.util.ActionRequestWrapper;
/**
* Default implementation of the {@link MultipartActionRequest} interface.
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractController.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractController.java
index fe7a6eea0810475c5bf187faadf3496479335771..6e824099ef9e5d5149e8ead48b758dd7cdef2792 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractController.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/AbstractController.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -122,6 +122,8 @@ import org.springframework.web.portlet.util.PortletUtils;
* @author John A. Lewis
* @author Juergen Hoeller
* @since 2.0
+ * @see ResourceAwareController
+ * @see EventAwareController
*/
public abstract class AbstractController extends PortletContentGenerator implements Controller {
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/Controller.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/Controller.java
index bfb49294be0f03a537526f8b694b8ba3ad7fe0c7..356898f97ba2ebedd7481d389fa7a9c16a9aa590 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/Controller.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/Controller.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2006 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -45,15 +45,7 @@ import org.springframework.web.portlet.ModelAndView;
* request and - if applicable - returning an appropriate ModelAndView.
* So actually, these method are the main entrypoint for the
* {@link org.springframework.web.portlet.DispatcherPortlet DispatcherPortlet}
- * which delegates requests to controllers. These method - and also this interface -
- * should preferrably not be implemented by custom controllers directly, since
- * abstract controllers also provided by this package already provide a lot of
- * functionality for typical use cases in portlet applications. A few examples of
- * those controllers:
- * {@link AbstractController AbstractController},
- * {@link AbstractCommandController AbstractCommandController},
- * {@link AbstractFormController AbstractFormController},
- * {@link SimpleFormController SimpleFormController}.
+ * which delegates requests to controllers.
*
*
So basically any direct implementation of the Controller interface
* just handles RenderRequests/ActionRequests and should return a ModelAndView, to be
@@ -64,19 +56,16 @@ import org.springframework.web.portlet.ModelAndView;
* @author William G. Thompson, Jr.
* @author John A. Lewis
* @since 2.0
+ * @see ResourceAwareController
+ * @see EventAwareController
* @see SimpleControllerHandlerAdapter
* @see AbstractController
- * @see AbstractCommandController
- * @see AbstractFormController
- * @see SimpleFormController
- * @see org.springframework.context.ApplicationContextAware
- * @see org.springframework.context.ResourceLoaderAware
* @see org.springframework.web.portlet.context.PortletContextAware
*/
public interface Controller {
/**
- * Process the action request. There is nothing to return.
+ * Process the action request. There is nothing to return.
* @param request current portlet action request
* @param response current portlet action response
* @throws Exception in case of errors
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/EventAwareController.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/EventAwareController.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd692733e2bfa6a663b962745b9326db8bc05d2c
--- /dev/null
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/EventAwareController.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2002-2009 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.web.portlet.mvc;
+
+import javax.portlet.EventRequest;
+import javax.portlet.EventResponse;
+
+/**
+ * Extension of the Portlet {@link Controller} interface that allows
+ * for handling Portlet 2.0 event requests as well. Can also be
+ * implemented by {@link AbstractController} subclasses.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ * @see javax.portlet.EventPortlet
+ * @see Controller
+ * @see ResourceAwareController
+ */
+public interface EventAwareController {
+
+ /**
+ * Process the event request. There is nothing to return.
+ * @param request current portlet event request
+ * @param response current portlet event response
+ * @throws Exception in case of errors
+ */
+ void handleEventRequest(EventRequest request, EventResponse response) throws Exception;
+
+}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/PortletWrappingController.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/PortletWrappingController.java
index c8dcb3784a29b07cbd20007ce702b6f089ef2b07..9ff142f5009d037b8a8e9cdbd93b5afb1510e447 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/PortletWrappingController.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/PortletWrappingController.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2006 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -16,11 +16,13 @@
package org.springframework.web.portlet.mvc;
+import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.Locale;
-import java.util.Properties;
+import java.util.Map;
import java.util.ResourceBundle;
-
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.Portlet;
@@ -28,6 +30,8 @@ import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
@@ -79,7 +83,7 @@ public class PortletWrappingController extends AbstractController
private String portletName;
- private Properties initParameters = new Properties();
+ private Map initParameters = new LinkedHashMap();
private String beanName;
@@ -128,7 +132,7 @@ public class PortletWrappingController extends AbstractController
* Specify init parameters for the portlet to wrap,
* as name-value pairs.
*/
- public void setInitParameters(Properties initParameters) {
+ public void setInitParameters(Map initParameters) {
this.initParameters = initParameters;
}
@@ -195,17 +199,40 @@ public class PortletWrappingController extends AbstractController
}
public String getInitParameter(String paramName) {
- return initParameters.getProperty(paramName);
+ return initParameters.get(paramName);
}
- public Enumeration getInitParameterNames() {
- return initParameters.keys();
+ public Enumeration getInitParameterNames() {
+ return Collections.enumeration(initParameters.keySet());
}
public ResourceBundle getResourceBundle(Locale locale) {
return (portletConfig != null ? portletConfig.getResourceBundle(locale) : null);
}
+ public Enumeration getPublicRenderParameterNames() {
+ return Collections.enumeration(new HashSet());
+ }
+
+ public String getDefaultNamespace() {
+ return XMLConstants.NULL_NS_URI;
+ }
+
+ public Enumeration getPublishingEventQNames() {
+ return Collections.enumeration(new HashSet());
+ }
+
+ public Enumeration getProcessingEventQNames() {
+ return Collections.enumeration(new HashSet());
+ }
+
+ public Enumeration getSupportedLocales() {
+ return Collections.enumeration(new HashSet());
+ }
+
+ public Map getContainerRuntimeOptions() {
+ return (portletConfig != null ? portletConfig.getContainerRuntimeOptions() : null);
+ }
}
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/ResourceAwareController.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/ResourceAwareController.java
new file mode 100644
index 0000000000000000000000000000000000000000..24ad45d76b97f52bf40e2915fa57a32132693ee4
--- /dev/null
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/ResourceAwareController.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2002-2009 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.web.portlet.mvc;
+
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
+
+import org.springframework.web.portlet.ModelAndView;
+
+/**
+ * Extension of the Portlet {@link Controller} interface that allows
+ * for handling Portlet 2.0 resource requests as well. Can also be
+ * implemented by {@link AbstractController} subclasses.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ * @see javax.portlet.ResourceServingPortlet
+ * @see Controller
+ * @see EventAwareController
+ */
+public interface ResourceAwareController {
+
+ /**
+ * Process the resource request and return a ModelAndView object which the DispatcherPortlet
+ * will render. A null return value is not an error: It indicates that this
+ * object completed request processing itself, thus there is no ModelAndView to render.
+ * @param request current portlet resource request
+ * @param response current portlet resource response
+ * @return a ModelAndView to render, or null if handled directly
+ * @throws Exception in case of errors
+ */
+ ModelAndView handleResourceRequest(ResourceRequest request, ResourceResponse response) throws Exception;
+
+}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/SimpleControllerHandlerAdapter.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/SimpleControllerHandlerAdapter.java
index 5eac5c4ae180df346b6e8c17ab5400b5c9722e37..d0a3ba7edbfdfa78efb26c0c5176afec2a758c4d 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/SimpleControllerHandlerAdapter.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/SimpleControllerHandlerAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2006 the original author or authors.
+ * Copyright 2002-2009 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,24 +18,42 @@ package org.springframework.web.portlet.mvc;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
+import javax.portlet.EventRequest;
+import javax.portlet.EventResponse;
+import javax.portlet.PortletContext;
+import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
import org.springframework.web.portlet.HandlerAdapter;
import org.springframework.web.portlet.ModelAndView;
+import org.springframework.web.portlet.context.PortletContextAware;
/**
* Adapter to use the Controller workflow interface with the generic DispatcherPortlet.
*
*
This is an SPI class, not used directly by application code.
*
+ * @author Juergen Hoeller
* @author John A. Lewis
* @since 2.0
* @see org.springframework.web.portlet.DispatcherPortlet
* @see Controller
- */
-public class SimpleControllerHandlerAdapter implements HandlerAdapter {
-
+ * @see ResourceAwareController
+ * @see EventAwareController
+ */
+public class SimpleControllerHandlerAdapter implements HandlerAdapter, PortletContextAware {
+
+ private PortletContext portletContext;
+
+
+ public void setPortletContext(PortletContext portletContext) {
+ this.portletContext = portletContext;
+ }
+
+
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
@@ -52,4 +70,32 @@ public class SimpleControllerHandlerAdapter implements HandlerAdapter {
return ((Controller) handler).handleRenderRequest(request, response);
}
+ public ModelAndView handleResource(ResourceRequest request, ResourceResponse response, Object handler)
+ throws Exception {
+
+ if (handler instanceof ResourceAwareController) {
+ return ((ResourceAwareController) handler).handleResourceRequest(request, response);
+ }
+ else {
+ // equivalent to Portlet 2.0 GenericPortlet
+ if (request.getResourceID() != null) {
+ PortletRequestDispatcher rd = this.portletContext.getRequestDispatcher(request.getResourceID());
+ if (rd != null) {
+ rd.forward(request, response);
+ }
+ }
+ return null;
+ }
+ }
+
+ public void handleEvent(EventRequest request, EventResponse response, Object handler) throws Exception {
+ if (handler instanceof EventAwareController) {
+ ((EventAwareController) handler).handleEventRequest(request, response);
+ }
+ else {
+ // if no event processing method was found just keep render params
+ response.setRenderParameters(request);
+ }
+ }
+
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerAdapter.java
index c8e20c22f52f6aced0cee23bd4ae010560a5876f..94ce35562008479503fcb00e3c54e3f7d7f58062 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerAdapter.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -23,13 +23,20 @@ import java.io.Writer;
import java.lang.reflect.Method;
import java.security.Principal;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
+import javax.portlet.ClientDataRequest;
+import javax.portlet.Event;
+import javax.portlet.EventRequest;
+import javax.portlet.EventResponse;
+import javax.portlet.MimeResponse;
import javax.portlet.PortalContext;
import javax.portlet.PortletException;
import javax.portlet.PortletMode;
@@ -39,6 +46,8 @@ import javax.portlet.PortletResponse;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
import javax.portlet.UnavailableException;
import javax.portlet.WindowState;
@@ -54,11 +63,14 @@ import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
import org.springframework.validation.support.BindingAwareModelMap;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.annotation.support.HandlerMethodInvoker;
@@ -72,6 +84,10 @@ import org.springframework.web.portlet.HandlerAdapter;
import org.springframework.web.portlet.ModelAndView;
import org.springframework.web.portlet.bind.MissingPortletRequestParameterException;
import org.springframework.web.portlet.bind.PortletRequestDataBinder;
+import org.springframework.web.portlet.bind.annotation.ActionMapping;
+import org.springframework.web.portlet.bind.annotation.EventMapping;
+import org.springframework.web.portlet.bind.annotation.RenderMapping;
+import org.springframework.web.portlet.bind.annotation.ResourceMapping;
import org.springframework.web.portlet.context.PortletWebRequest;
import org.springframework.web.portlet.handler.PortletContentGenerator;
import org.springframework.web.portlet.handler.PortletSessionRequiredException;
@@ -218,14 +234,25 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
return doHandle(request, response, handler);
}
+ public ModelAndView handleResource(ResourceRequest request, ResourceResponse response, Object handler) throws Exception {
+ checkAndPrepare(request, response);
+ return doHandle(request, response, handler);
+ }
+
+ public void handleEvent(EventRequest request, EventResponse response, Object handler) throws Exception {
+ Object returnValue = doHandle(request, response, handler);
+ if (returnValue != null) {
+ throw new IllegalStateException("Invalid action method return value: " + returnValue);
+ }
+ }
+
protected ModelAndView doHandle(PortletRequest request, PortletResponse response, Object handler) throws Exception {
ExtendedModelMap implicitModel = null;
- if (request instanceof RenderRequest && response instanceof RenderResponse) {
- RenderRequest renderRequest = (RenderRequest) request;
- RenderResponse renderResponse = (RenderResponse) response;
+ if (response instanceof MimeResponse) {
+ MimeResponse mimeResponse = (MimeResponse) response;
// Detect implicit model from associated action phase.
- if (renderRequest.getParameter(IMPLICIT_MODEL_ATTRIBUTE) != null) {
+ if (request.getParameter(IMPLICIT_MODEL_ATTRIBUTE) != null) {
PortletSession session = request.getPortletSession(false);
if (session != null) {
implicitModel = (ExtendedModelMap) session.getAttribute(IMPLICIT_MODEL_ATTRIBUTE);
@@ -233,11 +260,11 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
}
if (handler.getClass().getAnnotation(SessionAttributes.class) != null) {
// Always prevent caching in case of session attribute management.
- checkAndPrepare(renderRequest, renderResponse, this.cacheSecondsForSessionAttributeHandlers);
+ checkAndPrepare(request, mimeResponse, this.cacheSecondsForSessionAttributeHandlers);
}
else {
// Uses configured default cacheSeconds setting.
- checkAndPrepare(renderRequest, renderResponse);
+ checkAndPrepare(request, mimeResponse);
}
}
@@ -265,7 +292,7 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
PortletWebRequest webRequest = new PortletWebRequest(request, response);
PortletHandlerMethodResolver methodResolver = getMethodResolver(handler);
- Method handlerMethod = methodResolver.resolveHandlerMethod(request, response);
+ Method handlerMethod = methodResolver.resolveHandlerMethod(request);
PortletHandlerMethodInvoker methodInvoker = new PortletHandlerMethodInvoker(methodResolver);
Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
@@ -324,42 +351,51 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
private static class PortletHandlerMethodResolver extends HandlerMethodResolver {
+ private final Map mappings = new HashMap();
+
public PortletHandlerMethodResolver(Class> handlerType) {
- super(handlerType);
+ init(handlerType);
}
- public Method resolveHandlerMethod(PortletRequest request, PortletResponse response) throws PortletException {
- String lookupMode = request.getPortletMode().toString();
+ @Override
+ protected boolean isHandlerMethod(Method method) {
+ RequestMappingInfo mappingInfo = new RequestMappingInfo();
+ RequestMapping requestMapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);
+ ActionMapping actionMapping = AnnotationUtils.findAnnotation(method, ActionMapping.class);
+ RenderMapping renderMapping = AnnotationUtils.findAnnotation(method, RenderMapping.class);
+ ResourceMapping resourceMapping = AnnotationUtils.findAnnotation(method, ResourceMapping.class);
+ EventMapping eventMapping = AnnotationUtils.findAnnotation(method, EventMapping.class);
+ if (actionMapping != null) {
+ mappingInfo.initPhaseMapping(PortletRequest.ACTION_PHASE, actionMapping.value(), actionMapping.params());
+ }
+ if (renderMapping != null) {
+ mappingInfo.initPhaseMapping(PortletRequest.RENDER_PHASE, renderMapping.value(), renderMapping.params());
+ }
+ if (resourceMapping != null) {
+ mappingInfo.initPhaseMapping(PortletRequest.RESOURCE_PHASE, resourceMapping.value(), resourceMapping.params());
+ }
+ if (eventMapping != null) {
+ mappingInfo.initPhaseMapping(PortletRequest.EVENT_PHASE, eventMapping.value(), eventMapping.params());
+ }
+ if (requestMapping != null) {
+ mappingInfo.initStandardMapping(requestMapping.value(), requestMapping.method(), requestMapping.params());
+ if (mappingInfo.phase == null) {
+ mappingInfo.phase = determineDefaultPhase(method);
+ }
+ }
+ this.mappings.put(method, mappingInfo);
+ return (mappingInfo.phase != null);
+ }
+
+ public Method resolveHandlerMethod(PortletRequest request) throws PortletException {
Map targetHandlerMethods = new LinkedHashMap();
for (Method handlerMethod : getHandlerMethods()) {
- RequestMapping mapping = AnnotationUtils.findAnnotation(handlerMethod, RequestMapping.class);
- RequestMappingInfo mappingInfo = new RequestMappingInfo();
- mappingInfo.modes = mapping.value();
- mappingInfo.params = mapping.params();
- mappingInfo.action = isActionMethod(handlerMethod);
- mappingInfo.render = isRenderMethod(handlerMethod);
- boolean match = false;
- if (mappingInfo.modes.length > 0) {
- for (String mappedMode : mappingInfo.modes) {
- if (mappedMode.equalsIgnoreCase(lookupMode)) {
- if (checkParameters(request, response, mappingInfo)) {
- match = true;
- }
- else {
- break;
- }
- }
- }
- }
- else {
- // No modes specified: parameter match sufficient.
- match = checkParameters(request, response, mappingInfo);
- }
- if (match) {
+ RequestMappingInfo mappingInfo = this.mappings.get(handlerMethod);
+ if (mappingInfo.match(request)) {
Method oldMappedMethod = targetHandlerMethods.put(mappingInfo, handlerMethod);
if (oldMappedMethod != null && oldMappedMethod != handlerMethod) {
throw new IllegalStateException("Ambiguous handler methods mapped for portlet mode '" +
- lookupMode + "': {" + oldMappedMethod + ", " + handlerMethod +
+ request.getPortletMode() + "': {" + oldMappedMethod + ", " + handlerMethod +
"}. If you intend to handle the same mode in multiple methods, then factor " +
"them out into a dedicated handler class with that mode mapped at the type level!");
}
@@ -376,8 +412,7 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
bestMappingMatch = mapping;
}
else {
- if ((bestMappingMatch.modes.length == 0 && mapping.modes.length > 0) ||
- bestMappingMatch.params.length < mapping.params.length) {
+ if (mapping.isBetterMatchThan(bestMappingMatch)) {
bestMappingMatch = mapping;
}
}
@@ -386,50 +421,123 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
}
}
else {
- throw new UnavailableException("No matching handler method found for portlet request: mode '" +
- request.getPortletMode() + "', type '" + (response instanceof ActionResponse ? "action" : "render") +
+ throw new UnavailableException(
+ "No matching handler method found for portlet request: mode '" + request.getPortletMode() +
+ "', phase '" + request.getAttribute(PortletRequest.LIFECYCLE_PHASE) +
"', parameters " + StylerUtils.style(request.getParameterMap()));
}
}
- private boolean checkParameters(PortletRequest request, PortletResponse response, RequestMappingInfo mapping) {
- if (response instanceof RenderResponse) {
- if (mapping.action) {
- return false;
- }
- }
- else if (response instanceof ActionResponse) {
- if (mapping.render) {
- return false;
- }
- }
- return PortletAnnotationMappingUtils.checkParameters(mapping.params, request);
- }
-
- private boolean isActionMethod(Method handlerMethod) {
+ private String determineDefaultPhase(Method handlerMethod) {
if (!void.class.equals(handlerMethod.getReturnType())) {
- return false;
+ return PortletRequest.RENDER_PHASE;
}
for (Class> argType : handlerMethod.getParameterTypes()) {
if (ActionRequest.class.isAssignableFrom(argType) || ActionResponse.class.isAssignableFrom(argType) ||
InputStream.class.isAssignableFrom(argType) || Reader.class.isAssignableFrom(argType)) {
- return true;
+ return PortletRequest.ACTION_PHASE;
+ }
+ else if (RenderRequest.class.isAssignableFrom(argType) || RenderResponse.class.isAssignableFrom(argType) ||
+ OutputStream.class.isAssignableFrom(argType) || Writer.class.isAssignableFrom(argType)) {
+ return PortletRequest.RENDER_PHASE;
+ }
+ else if (ResourceRequest.class.isAssignableFrom(argType) || ResourceResponse.class.isAssignableFrom(argType)) {
+ return PortletRequest.RESOURCE_PHASE;
+ }
+ else if (EventRequest.class.isAssignableFrom(argType) || EventResponse.class.isAssignableFrom(argType)) {
+ return PortletRequest.EVENT_PHASE;
}
}
- return false;
+ return "";
}
+ }
- private boolean isRenderMethod(Method handlerMethod) {
- if (!void.class.equals(handlerMethod.getReturnType())) {
- return true;
+
+ private static class RequestMappingInfo {
+
+ public Set modes = new HashSet();
+
+ public String phase;
+
+ public String value;
+
+ public Set methods = new HashSet();
+
+ public String[] params = new String[0];
+
+ public void initStandardMapping(String[] modes, RequestMethod[] methods, String[] params) {
+ for (String mode : modes) {
+ this.modes.add(new PortletMode(mode));
}
- for (Class> argType : handlerMethod.getParameterTypes()) {
- if (RenderRequest.class.isAssignableFrom(argType) || RenderResponse.class.isAssignableFrom(argType) ||
- OutputStream.class.isAssignableFrom(argType) || Writer.class.isAssignableFrom(argType)) {
- return true;
+ for (RequestMethod method : methods) {
+ this.methods.add(method.name());
+ }
+ this.params = StringUtils.mergeStringArrays(this.params, params);
+ }
+
+ public void initPhaseMapping(String phase, String value, String[] params) {
+ if (this.phase != null) {
+ throw new IllegalStateException(
+ "Invalid mapping - more than one phase specified: '" + this.phase + "', '" + phase + "'");
+ }
+ this.phase = phase;
+ this.value = value;
+ this.params = StringUtils.mergeStringArrays(this.params, params);
+ }
+
+ public boolean match(PortletRequest request) {
+ if (!this.modes.isEmpty() && !this.modes.contains(request.getPortletMode())) {
+ return false;
+ }
+ if (StringUtils.hasLength(this.phase) &&
+ !this.phase.equals(request.getAttribute(PortletRequest.LIFECYCLE_PHASE))) {
+ return false;
+ }
+ if (StringUtils.hasLength(this.value)) {
+ if (this.phase.equals(PortletRequest.ACTION_PHASE) &&
+ !this.value.equals(request.getParameter(ActionRequest.ACTION_NAME))) {
+ return false;
+ }
+ else if (this.phase.equals(PortletRequest.RENDER_PHASE) &&
+ !(new WindowState(this.value)).equals(request.getWindowState())) {
+ return false;
+ }
+ else if (this.phase.equals(PortletRequest.RESOURCE_PHASE) &&
+ !this.value.equals(((ResourceRequest) request).getResourceID())) {
+ return false;
+ }
+ else if (this.phase.equals(PortletRequest.EVENT_PHASE)) {
+ Event event = ((EventRequest) request).getEvent();
+ if (!this.value.equals(event.getName()) && !this.value.equals(event.getQName().toString())) {
+ return false;
+ }
}
}
- return false;
+ return PortletAnnotationMappingUtils.checkRequestMethod(this.methods, request) &&
+ PortletAnnotationMappingUtils.checkParameters(this.params, request);
+ }
+
+ public boolean isBetterMatchThan(RequestMappingInfo other) {
+ return ((!this.modes.isEmpty() && other.modes.isEmpty()) ||
+ (StringUtils.hasLength(this.phase) && !StringUtils.hasLength(other.phase)) ||
+ (StringUtils.hasLength(this.value) && !StringUtils.hasLength(other.value)) ||
+ (!this.methods.isEmpty() && other.methods.isEmpty()) ||
+ this.params.length > other.params.length);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ RequestMappingInfo other = (RequestMappingInfo) obj;
+ return (this.modes.equals(other.modes) &&
+ ObjectUtils.nullSafeEquals(this.phase, other.phase) &&
+ ObjectUtils.nullSafeEquals(this.value, other.value) &&
+ this.methods.equals(other.methods) &&
+ Arrays.equals(this.params, other.params));
+ }
+
+ @Override
+ public int hashCode() {
+ return (ObjectUtils.nullSafeHashCode(this.modes) * 29 + this.phase.hashCode());
}
}
@@ -505,28 +613,34 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
return request.getLocale();
}
else if (InputStream.class.isAssignableFrom(parameterType)) {
- if (!(request instanceof ActionRequest)) {
- throw new IllegalStateException("InputStream can only get obtained for ActionRequest");
+ if (!(request instanceof ClientDataRequest)) {
+ throw new IllegalStateException("InputStream can only get obtained for Action/ResourceRequest");
}
- return ((ActionRequest) request).getPortletInputStream();
+ return ((ClientDataRequest) request).getPortletInputStream();
}
else if (Reader.class.isAssignableFrom(parameterType)) {
- if (!(request instanceof ActionRequest)) {
- throw new IllegalStateException("Reader can only get obtained for ActionRequest");
+ if (!(request instanceof ClientDataRequest)) {
+ throw new IllegalStateException("Reader can only get obtained for Action/ResourceRequest");
}
- return ((ActionRequest) request).getReader();
+ return ((ClientDataRequest) request).getReader();
}
else if (OutputStream.class.isAssignableFrom(parameterType)) {
- if (!(response instanceof RenderResponse)) {
- throw new IllegalStateException("OutputStream can only get obtained for RenderResponse");
+ if (!(response instanceof MimeResponse)) {
+ throw new IllegalStateException("OutputStream can only get obtained for Render/ResourceResponse");
}
- return ((RenderResponse) response).getPortletOutputStream();
+ return ((MimeResponse) response).getPortletOutputStream();
}
else if (Writer.class.isAssignableFrom(parameterType)) {
- if (!(response instanceof RenderResponse)) {
- throw new IllegalStateException("Writer can only get obtained for RenderResponse");
+ if (!(response instanceof MimeResponse)) {
+ throw new IllegalStateException("Writer can only get obtained for Render/ResourceResponse");
+ }
+ return ((MimeResponse) response).getWriter();
+ }
+ else if (Event.class.equals(parameterType)) {
+ if (!(request instanceof EventRequest)) {
+ throw new IllegalStateException("Event can only get obtained from EventRequest");
}
- return ((RenderResponse) response).getWriter();
+ return ((EventRequest) request).getEvent();
}
return super.resolveStandardArgument(parameterType, webRequest);
}
@@ -581,28 +695,4 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
}
}
-
- private static class RequestMappingInfo {
-
- public String[] modes = new String[0];
-
- public String[] params = new String[0];
-
- private boolean action = false;
-
- private boolean render = false;
-
- @Override
- public boolean equals(Object obj) {
- RequestMappingInfo other = (RequestMappingInfo) obj;
- return (this.action == other.action && this.render == other.render &&
- Arrays.equals(this.modes, other.modes) && Arrays.equals(this.params, other.params));
- }
-
- @Override
- public int hashCode() {
- return (Arrays.hashCode(this.modes) * 29 + Arrays.hashCode(this.params));
- }
- }
-
}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/DefaultAnnotationHandlerMapping.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/DefaultAnnotationHandlerMapping.java
index 2ae1422bd98fef135e3eb4ff84bcc710275d4ec6..473eb5052640ae482fa8182a2f0efed19fe14b73 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/DefaultAnnotationHandlerMapping.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/DefaultAnnotationHandlerMapping.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -16,9 +16,12 @@
package org.springframework.web.portlet.mvc.annotation;
+import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
+import javax.portlet.ClientDataRequest;
+import javax.portlet.PortletException;
import javax.portlet.PortletMode;
import javax.portlet.PortletRequest;
@@ -28,8 +31,11 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Controller;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.Mapping;
import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.portlet.handler.AbstractMapBasedHandlerMapping;
+import org.springframework.web.portlet.handler.PortletRequestMethodNotSupportedException;
/**
* Implementation of the {@link org.springframework.web.portlet.HandlerMapping}
@@ -99,12 +105,13 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp
if (mapping != null) {
String[] modeKeys = mapping.value();
String[] params = mapping.params();
+ RequestMethod[] methods = mapping.method();
boolean registerHandlerType = true;
if (modeKeys.length == 0 || params.length == 0) {
registerHandlerType = !detectHandlerMethods(handlerType, beanName, mapping);
}
if (registerHandlerType) {
- ParameterMappingPredicate predicate = new ParameterMappingPredicate(params);
+ ParameterMappingPredicate predicate = new ParameterMappingPredicate(params, methods);
for (String modeKey : modeKeys) {
registerHandler(new PortletMode(modeKey), beanName, predicate);
}
@@ -128,9 +135,20 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp
final Set handlersRegistered = new HashSet(1);
ReflectionUtils.doWithMethods(handlerType, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) {
- RequestMapping mapping = method.getAnnotation(RequestMapping.class);
- if (mapping != null) {
- String[] modeKeys = mapping.value();
+ boolean mappingFound = false;
+ String[] modeKeys = new String[0];
+ String[] params = new String[0];
+ for (Annotation ann : method.getAnnotations()) {
+ if (AnnotationUtils.findAnnotation(ann.getClass(), Mapping.class) != null) {
+ mappingFound = true;
+ if (ann instanceof RequestMapping) {
+ modeKeys = (String[]) AnnotationUtils.getValue(ann);
+ }
+ String[] specificParams = (String[]) AnnotationUtils.getValue(ann, "params");
+ params = StringUtils.mergeStringArrays(params, specificParams);
+ }
+ }
+ if (mappingFound) {
if (modeKeys.length == 0) {
if (typeMapping != null) {
modeKeys = typeMapping.value();
@@ -140,7 +158,6 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp
"No portlet mode mappings specified - neither at type nor method level");
}
}
- String[] params = mapping.params();
if (typeMapping != null) {
PortletAnnotationMappingUtils.validateModeMapping(modeKeys, typeMapping.value());
params = StringUtils.mergeStringArrays(typeMapping.params(), params);
@@ -172,14 +189,35 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp
private final String[] params;
- private ParameterMappingPredicate(String[] params) {
+ private final Set methods = new HashSet();
+
+ public ParameterMappingPredicate(String[] params) {
+ this.params = params;
+ }
+
+ public ParameterMappingPredicate(String[] params, RequestMethod[] methods) {
this.params = params;
+ for (RequestMethod method : methods) {
+ this.methods.add(method.name());
+ }
}
public boolean match(PortletRequest request) {
return PortletAnnotationMappingUtils.checkParameters(this.params, request);
}
+ public void validate(PortletRequest request) throws PortletException {
+ if (!this.methods.isEmpty()) {
+ if (!(request instanceof ClientDataRequest)) {
+ throw new PortletRequestMethodNotSupportedException(StringUtils.toStringArray(this.methods));
+ }
+ String method = ((ClientDataRequest) request).getMethod();
+ if (!this.methods.contains(method)) {
+ throw new PortletRequestMethodNotSupportedException(method, StringUtils.toStringArray(this.methods));
+ }
+ }
+ }
+
public int compareTo(Object other) {
if (other instanceof PortletRequestMappingPredicate) {
return new Integer(((ParameterMappingPredicate) other).params.length).compareTo(this.params.length);
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/PortletAnnotationMappingUtils.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/PortletAnnotationMappingUtils.java
index cb8edf7062aef850bd1d065b8b5364ceff042ce3..71c1db87d1adb6c083d9338cebd382fb1e530a45 100644
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/PortletAnnotationMappingUtils.java
+++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/PortletAnnotationMappingUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -16,6 +16,8 @@
package org.springframework.web.portlet.mvc.annotation;
+import java.util.Set;
+import javax.portlet.ClientDataRequest;
import javax.portlet.PortletRequest;
import org.springframework.util.ObjectUtils;
@@ -30,7 +32,7 @@ import org.springframework.web.portlet.util.PortletUtils;
abstract class PortletAnnotationMappingUtils {
/**
- * Check whether the given request matches the specified request methods.
+ * Check whether the given portlet modes matches the specified type-level modes.
* @param modes the mapped portlet modes to check
* @param typeLevelModes the type-level mode mappings to check against
*/
@@ -51,11 +53,29 @@ abstract class PortletAnnotationMappingUtils {
return true;
}
+ /**
+ * Check whether the given request matches the specified request methods.
+ * @param methods the request methods to check against
+ * @param request the current request to check
+ */
+ public static boolean checkRequestMethod(Set methods, PortletRequest request) {
+ if (!methods.isEmpty()) {
+ if (!(request instanceof ClientDataRequest)) {
+ return false;
+ }
+ String method = ((ClientDataRequest) request).getMethod();
+ if (!methods.contains(method)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Check whether the given request matches the specified parameter conditions.
* @param params the parameter conditions, following
* {@link org.springframework.web.bind.annotation.RequestMapping#params()}
- * @param request the current HTTP request to check
+ * @param request the current request to check
*/
public static boolean checkParameters(String[] params, PortletRequest request) {
if (!ObjectUtils.isEmpty(params)) {
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/util/ActionRequestWrapper.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/util/ActionRequestWrapper.java
deleted file mode 100644
index 3993af1f9c0176948bb1fb99bf6e7398e0d73938..0000000000000000000000000000000000000000
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/util/ActionRequestWrapper.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2002-2006 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.web.portlet.util;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-
-import javax.portlet.ActionRequest;
-
-/**
- * Simple wrapper for a Portlet {@link javax.portlet.ActionRequest},
- * delegating all calls to the underlying request.
- *
- *
(In the style of the Servlet API's {@link javax.servlet.http.HttpServletRequestWrapper}.)
- *
- * @author Juergen Hoeller
- * @since 2.0
- * @see ActionRequestWrapper
- * @see javax.servlet.http.HttpServletRequestWrapper
- */
-public class ActionRequestWrapper extends PortletRequestWrapper implements ActionRequest {
-
- /** Original request that we're delegating to */
- private final ActionRequest actionRequest;
-
-
- /**
- * Create a ActionRequestWrapper for the given request.
- * @param request the original request to wrap
- * @throws IllegalArgumentException if the supplied request is null
- */
- public ActionRequestWrapper(ActionRequest request) {
- super(request);
- this.actionRequest = request;
- }
-
-
- public InputStream getPortletInputStream() throws IOException {
- return this.actionRequest.getPortletInputStream();
- }
-
- public void setCharacterEncoding(String enc) throws UnsupportedEncodingException {
- this.actionRequest.setCharacterEncoding(enc);
- }
-
- public BufferedReader getReader() throws IOException {
- return this.actionRequest.getReader();
- }
-
- public String getCharacterEncoding() {
- return this.actionRequest.getCharacterEncoding();
- }
-
- public String getContentType() {
- return this.actionRequest.getContentType();
- }
-
- public int getContentLength() {
- return this.actionRequest.getContentLength();
- }
-
-}
diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/util/PortletRequestWrapper.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/util/PortletRequestWrapper.java
deleted file mode 100644
index 9c65318e1320b8f50dcb57d1ae7c4773b476284d..0000000000000000000000000000000000000000
--- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/util/PortletRequestWrapper.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright 2002-2006 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.web.portlet.util;
-
-import java.util.Enumeration;
-import java.util.Locale;
-import java.util.Map;
-import java.security.Principal;
-
-import javax.portlet.PortalContext;
-import javax.portlet.PortletMode;
-import javax.portlet.PortletPreferences;
-import javax.portlet.PortletRequest;
-import javax.portlet.PortletSession;
-import javax.portlet.WindowState;
-
-import org.springframework.util.Assert;
-
-/**
- * Simple wrapper for a {@link javax.portlet.PortletRequest}, delegating all
- * calls to the underlying request.
- *
- *
(In the style of the Servlet API's {@link javax.servlet.ServletRequestWrapper}.)
- *
- * @author Juergen Hoeller
- * @since 2.0
- * @see ActionRequestWrapper
- * @see javax.servlet.ServletRequestWrapper
- */
-public class PortletRequestWrapper implements PortletRequest {
-
- /** Original request that we're delegating to */
- private final PortletRequest portletRequest;
-
-
- /**
- * Create a PortletRequestWrapper for the given {@link javax.portlet.PortletRequest}.
- * @param request the original {@link javax.portlet.PortletRequest} to wrap
- * @throws IllegalArgumentException if the supplied request is null
- */
- public PortletRequestWrapper(PortletRequest request) {
- Assert.notNull(request, "Request is required");
- this.portletRequest = request;
- }
-
-
- public boolean isWindowStateAllowed(WindowState state) {
- return this.portletRequest.isWindowStateAllowed(state);
- }
-
- public boolean isPortletModeAllowed(PortletMode mode) {
- return this.portletRequest.isPortletModeAllowed(mode);
- }
-
- public PortletMode getPortletMode() {
- return this.portletRequest.getPortletMode();
- }
-
- public WindowState getWindowState() {
- return this.portletRequest.getWindowState();
- }
-
- public PortletPreferences getPreferences() {
- return this.portletRequest.getPreferences();
- }
-
- public PortletSession getPortletSession() {
- return this.portletRequest.getPortletSession();
- }
-
- public PortletSession getPortletSession(boolean create) {
- return this.portletRequest.getPortletSession(create);
- }
-
- public String getProperty(String name) {
- return this.portletRequest.getProperty(name);
- }
-
- public Enumeration getProperties(String name) {
- return this.portletRequest.getProperties(name);
- }
-
- public Enumeration getPropertyNames() {
- return this.portletRequest.getPropertyNames();
- }
-
- public PortalContext getPortalContext() {
- return this.portletRequest.getPortalContext();
- }
-
- public String getAuthType() {
- return this.portletRequest.getAuthType();
- }
-
- public String getContextPath() {
- return this.portletRequest.getContextPath();
- }
-
- public String getRemoteUser() {
- return this.portletRequest.getRemoteUser();
- }
-
- public Principal getUserPrincipal() {
- return this.portletRequest.getUserPrincipal();
- }
-
- public boolean isUserInRole(String role) {
- return this.portletRequest.isUserInRole(role);
- }
-
- public Object getAttribute(String name) {
- return this.portletRequest.getAttribute(name);
- }
-
- public Enumeration getAttributeNames() {
- return this.portletRequest.getAttributeNames();
- }
-
- public String getParameter(String name) {
- return this.portletRequest.getParameter(name);
- }
-
- public Enumeration getParameterNames() {
- return this.portletRequest.getParameterNames();
- }
-
- public String[] getParameterValues(String name) {
- return this.portletRequest.getParameterValues(name);
- }
-
- public Map getParameterMap() {
- return this.portletRequest.getParameterMap();
- }
-
- public boolean isSecure() {
- return this.portletRequest.isSecure();
- }
-
- public void setAttribute(String name, Object value) {
- this.portletRequest.setAttribute(name, value);
- }
-
- public void removeAttribute(String name) {
- this.portletRequest.removeAttribute(name);
- }
-
- public String getRequestedSessionId() {
- return this.portletRequest.getRequestedSessionId();
- }
-
- public boolean isRequestedSessionIdValid() {
- return this.portletRequest.isRequestedSessionIdValid();
- }
-
- public String getResponseContentType() {
- return this.portletRequest.getResponseContentType();
- }
-
- public Enumeration getResponseContentTypes() {
- return this.portletRequest.getResponseContentTypes();
- }
-
- public Locale getLocale() {
- return this.portletRequest.getLocale();
- }
-
- public Enumeration getLocales() {
- return this.portletRequest.getLocales();
- }
-
- public String getScheme() {
- return this.portletRequest.getScheme();
- }
-
- public String getServerName() {
- return this.portletRequest.getServerName();
- }
-
- public int getServerPort() {
- return this.portletRequest.getServerPort();
- }
-
-}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionRequest.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionRequest.java
index e85da537d15127fea1953f90c73f01987489ea23..a687ccb6715d31b75adb9d76a58fa9cbec118b4a 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionRequest.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionRequest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2007 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -16,14 +16,6 @@
package org.springframework.mock.web.portlet;
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.UnsupportedEncodingException;
-
import javax.portlet.ActionRequest;
import javax.portlet.PortalContext;
import javax.portlet.PortletContext;
@@ -36,25 +28,28 @@ import javax.portlet.PortletMode;
* @author Juergen Hoeller
* @since 2.0
*/
-public class MockActionRequest extends MockPortletRequest implements ActionRequest {
-
- private String characterEncoding;
-
- private byte[] content;
-
- private String contentType;
-
+public class MockActionRequest extends MockClientDataRequest implements ActionRequest {
/**
* Create a new MockActionRequest with a default {@link MockPortalContext}
* and a default {@link MockPortletContext}.
- * @see MockPortalContext
- * @see MockPortletContext
+ * @see org.springframework.mock.web.portlet.MockPortalContext
+ * @see org.springframework.mock.web.portlet.MockPortletContext
*/
public MockActionRequest() {
super();
}
+ /**
+ * Create a new MockActionRequest with a default {@link MockPortalContext}
+ * and a default {@link MockPortletContext}.
+ * @param actionName the name of the action to trigger
+ */
+ public MockActionRequest(String actionName) {
+ super();
+ setParameter(ActionRequest.ACTION_NAME, actionName);
+ }
+
/**
* Create a new MockActionRequest with a default {@link MockPortalContext}
* and a default {@link MockPortletContext}.
@@ -83,49 +78,9 @@ public class MockActionRequest extends MockPortletRequest implements ActionReque
}
- public void setContent(byte[] content) {
- this.content = content;
- }
-
- public InputStream getPortletInputStream() throws IOException {
- if (this.content != null) {
- return new ByteArrayInputStream(this.content);
- }
- else {
- return null;
- }
- }
-
- public void setCharacterEncoding(String characterEncoding) {
- this.characterEncoding = characterEncoding;
- }
-
- public BufferedReader getReader() throws UnsupportedEncodingException {
- if (this.content != null) {
- InputStream sourceStream = new ByteArrayInputStream(this.content);
- Reader sourceReader = (this.characterEncoding != null) ?
- new InputStreamReader(sourceStream, this.characterEncoding) : new InputStreamReader(sourceStream);
- return new BufferedReader(sourceReader);
- }
- else {
- return null;
- }
- }
-
- public String getCharacterEncoding() {
- return characterEncoding;
- }
-
- public void setContentType(String contentType) {
- this.contentType = contentType;
- }
-
- public String getContentType() {
- return contentType;
- }
-
- public int getContentLength() {
- return (this.content != null ? content.length : -1);
+ @Override
+ protected String getLifecyclePhase() {
+ return ACTION_PHASE;
}
}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionResponse.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionResponse.java
index e608e81c49f53e3dfb457fbf1c2ffd8935cfdc77..e9c8587745b3ebfe219ffb95ad51df80a305bf5a 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionResponse.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockActionResponse.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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,9 @@
package org.springframework.mock.web.portlet;
import java.io.IOException;
+import java.io.Serializable;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -27,6 +29,7 @@ import javax.portlet.PortletMode;
import javax.portlet.PortletModeException;
import javax.portlet.WindowState;
import javax.portlet.WindowStateException;
+import javax.xml.namespace.QName;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -38,16 +41,12 @@ import org.springframework.util.CollectionUtils;
* @author Juergen Hoeller
* @since 2.0
*/
-public class MockActionResponse extends MockPortletResponse implements ActionResponse {
+public class MockActionResponse extends MockStateAwareResponse implements ActionResponse {
- private WindowState windowState;
-
- private PortletMode portletMode;
+ private boolean redirectAllowed = true;
private String redirectedUrl;
- private final Map renderParameters = new LinkedHashMap();
-
/**
* Create a new MockActionResponse with a default {@link MockPortalContext}.
@@ -71,93 +70,60 @@ public class MockActionResponse extends MockPortletResponse implements ActionRes
if (this.redirectedUrl != null) {
throw new IllegalStateException("Cannot set WindowState after sendRedirect has been called");
}
- if (!CollectionUtils.contains(getPortalContext().getSupportedWindowStates(), windowState)) {
- throw new WindowStateException("WindowState not supported", windowState);
- }
- this.windowState = windowState;
- }
-
- public WindowState getWindowState() {
- return windowState;
+ super.setWindowState(windowState);
+ this.redirectAllowed = false;
}
public void setPortletMode(PortletMode portletMode) throws PortletModeException {
if (this.redirectedUrl != null) {
throw new IllegalStateException("Cannot set PortletMode after sendRedirect has been called");
}
- if (!CollectionUtils.contains(getPortalContext().getSupportedPortletModes(), portletMode)) {
- throw new PortletModeException("PortletMode not supported", portletMode);
- }
- this.portletMode = portletMode;
- }
-
- public PortletMode getPortletMode() {
- return portletMode;
- }
-
- public void sendRedirect(String url) throws IOException {
- if (this.windowState != null || this.portletMode != null || !this.renderParameters.isEmpty()) {
- throw new IllegalStateException(
- "Cannot call sendRedirect after windowState, portletMode, or renderParameters have been set");
- }
- Assert.notNull(url, "Redirect URL must not be null");
- this.redirectedUrl = url;
+ super.setPortletMode(portletMode);
+ this.redirectAllowed = false;
}
- public String getRedirectedUrl() {
- return redirectedUrl;
- }
-
- public void setRenderParameters(Map parameters) {
+ public void setRenderParameters(Map parameters) {
if (this.redirectedUrl != null) {
throw new IllegalStateException("Cannot set render parameters after sendRedirect has been called");
}
- Assert.notNull(parameters, "Parameters Map must not be null");
- this.renderParameters.clear();
- for (Iterator it = parameters.entrySet().iterator(); it.hasNext();) {
- Map.Entry entry = (Map.Entry) it.next();
- Assert.isTrue(entry.getKey() instanceof String, "Key must be of type String");
- Assert.isTrue(entry.getValue() instanceof String[], "Value must be of type String[]");
- this.renderParameters.put((String) entry.getKey(), (String[]) entry.getValue());
- }
+ super.setRenderParameters(parameters);
+ this.redirectAllowed = false;
}
public void setRenderParameter(String key, String value) {
if (this.redirectedUrl != null) {
throw new IllegalStateException("Cannot set render parameters after sendRedirect has been called");
}
- Assert.notNull(key, "Parameter key must not be null");
- Assert.notNull(value, "Parameter value must not be null");
- this.renderParameters.put(key, new String[] {value});
- }
-
- public String getRenderParameter(String key) {
- Assert.notNull(key, "Parameter key must not be null");
- String[] arr = this.renderParameters.get(key);
- return (arr != null && arr.length > 0 ? arr[0] : null);
+ super.setRenderParameter(key, value);
+ this.redirectAllowed = false;
}
public void setRenderParameter(String key, String[] values) {
if (this.redirectedUrl != null) {
throw new IllegalStateException("Cannot set render parameters after sendRedirect has been called");
}
- Assert.notNull(key, "Parameter key must not be null");
- Assert.notNull(values, "Parameter values must not be null");
- this.renderParameters.put(key, values);
+ super.setRenderParameter(key, values);
+ this.redirectAllowed = false;
}
- public String[] getRenderParameterValues(String key) {
- Assert.notNull(key, "Parameter key must not be null");
- return this.renderParameters.get(key);
+ public void sendRedirect(String location) throws IOException {
+ if (!this.redirectAllowed) {
+ throw new IllegalStateException(
+ "Cannot call sendRedirect after windowState, portletMode, or renderParameters have been set");
+ }
+ Assert.notNull(location, "Redirect URL must not be null");
+ this.redirectedUrl = location;
}
- public Iterator getRenderParameterNames() {
- return this.renderParameters.keySet().iterator();
+ public void sendRedirect(String location, String renderUrlParamName) throws IOException {
+ sendRedirect(location);
+ if (renderUrlParamName != null) {
+ setRenderParameter(renderUrlParamName, location);
+ }
}
- public Map getRenderParameterMap() {
- return Collections.unmodifiableMap(this.renderParameters);
+ public String getRedirectedUrl() {
+ return this.redirectedUrl;
}
-
}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockBaseURL.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockBaseURL.java
new file mode 100644
index 0000000000000000000000000000000000000000..aad992058b9e697f232ab7c8bb6166fcc0bdbc1a
--- /dev/null
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockBaseURL.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2002-2009 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.mock.web.portlet;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.URLEncoder;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.portlet.BaseURL;
+import javax.portlet.PortletSecurityException;
+
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+/**
+ * Mock implementation of the {@link javax.portlet.BaseURL} interface.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public abstract class MockBaseURL implements BaseURL {
+
+ public static final String URL_TYPE_RENDER = "render";
+
+ public static final String URL_TYPE_ACTION = "action";
+
+ private static final String ENCODING = "UTF-8";
+
+
+ protected final Map parameters = new LinkedHashMap();
+
+ private boolean secure = false;
+
+ private final Map properties = new LinkedHashMap();
+
+
+ //---------------------------------------------------------------------
+ // BaseURL methods
+ //---------------------------------------------------------------------
+
+ public void setParameter(String key, String value) {
+ Assert.notNull(key, "Parameter key must be null");
+ Assert.notNull(value, "Parameter value must not be null");
+ this.parameters.put(key, new String[] {value});
+ }
+
+ public void setParameter(String key, String[] values) {
+ Assert.notNull(key, "Parameter key must be null");
+ Assert.notNull(values, "Parameter values must not be null");
+ this.parameters.put(key, values);
+ }
+
+ public void setParameters(Map parameters) {
+ Assert.notNull(parameters, "Parameters Map must not be null");
+ this.parameters.clear();
+ this.parameters.putAll(parameters);
+ }
+
+ public Set getParameterNames() {
+ return this.parameters.keySet();
+ }
+
+ public String getParameter(String name) {
+ String[] arr = this.parameters.get(name);
+ return (arr != null && arr.length > 0 ? arr[0] : null);
+ }
+
+ public String[] getParameterValues(String name) {
+ return this.parameters.get(name);
+ }
+
+ public Map getParameterMap() {
+ return Collections.unmodifiableMap(this.parameters);
+ }
+
+ public void setSecure(boolean secure) throws PortletSecurityException {
+ this.secure = secure;
+ }
+
+ public boolean isSecure() {
+ return this.secure;
+ }
+
+ public void write(Writer out) throws IOException {
+ out.write(toString());
+ }
+
+ public void write(Writer out, boolean escapeXML) throws IOException {
+ out.write(toString());
+ }
+
+ public void addProperty(String key, String value) {
+ String[] values = this.properties.get(key);
+ if (values != null) {
+ this.properties.put(key, StringUtils.addStringToArray(values, value));
+ }
+ else {
+ this.properties.put(key, new String[] {value});
+ }
+ }
+
+ public void setProperty(String key, String value) {
+ this.properties.put(key, new String[] {value});
+ }
+
+ public Map getProperties() {
+ return Collections.unmodifiableMap(this.properties);
+ }
+
+
+ protected String encodeParameter(String name, String value) {
+ try {
+ return URLEncoder.encode(name, ENCODING) + "=" + URLEncoder.encode(value, ENCODING);
+ }
+ catch (UnsupportedEncodingException ex) {
+ return null;
+ }
+ }
+
+ protected String encodeParameter(String name, String[] values) {
+ try {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0, n = values.length; i < n; i++) {
+ sb.append(i > 0 ? ";" : "").append(URLEncoder.encode(name, ENCODING)).append("=")
+ .append(URLEncoder.encode(values[i], ENCODING));
+ }
+ return sb.toString();
+ }
+ catch (UnsupportedEncodingException ex) {
+ return null;
+ }
+ }
+
+}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockCacheControl.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockCacheControl.java
new file mode 100644
index 0000000000000000000000000000000000000000..45dcae7d5eee62afbc65579e9def6a27e611e13d
--- /dev/null
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockCacheControl.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2002-2009 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.mock.web.portlet;
+
+import javax.portlet.CacheControl;
+
+/**
+ * Mock implementation of the {@link javax.portlet.CacheControl} interface.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class MockCacheControl implements CacheControl {
+
+ private int expirationTime = 0;
+
+ private boolean publicScope = false;
+
+ private String etag;
+
+ private boolean useCachedContent = false;
+
+
+ public int getExpirationTime() {
+ return this.expirationTime;
+ }
+
+ public void setExpirationTime(int time) {
+ this.expirationTime = time;
+ }
+
+ public boolean isPublicScope() {
+ return this.publicScope;
+ }
+
+ public void setPublicScope(boolean publicScope) {
+ this.publicScope = publicScope;
+ }
+
+ public String getETag() {
+ return this.etag;
+ }
+
+ public void setETag(String token) {
+ this.etag = token;
+ }
+
+ public boolean useCachedContent() {
+ return this.useCachedContent;
+ }
+
+ public void setUseCachedContent(boolean useCachedContent) {
+ this.useCachedContent = useCachedContent;
+ }
+
+}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockClientDataRequest.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockClientDataRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a71c7d7a832bfc9c86d92326d861ff64f4d1b0c
--- /dev/null
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockClientDataRequest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2002-2009 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.mock.web.portlet;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import javax.portlet.ClientDataRequest;
+import javax.portlet.PortalContext;
+import javax.portlet.PortletContext;
+import javax.portlet.PortletMode;
+
+/**
+ * Mock implementation of the {@link javax.portlet.ClientDataRequest} interface.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class MockClientDataRequest extends MockPortletRequest implements ClientDataRequest {
+
+ private String characterEncoding;
+
+ private byte[] content;
+
+ private String contentType;
+
+ private String method;
+
+
+ /**
+ * Create a new MockClientDataRequest with a default {@link MockPortalContext}
+ * and a default {@link MockPortletContext}.
+ * @see org.springframework.mock.web.portlet.MockPortalContext
+ * @see org.springframework.mock.web.portlet.MockPortletContext
+ */
+ public MockClientDataRequest() {
+ super();
+ }
+
+ /**
+ * Create a new MockClientDataRequest with a default {@link MockPortalContext}.
+ * @param portletContext the PortletContext that the request runs in
+ */
+ public MockClientDataRequest(PortletContext portletContext) {
+ super(portletContext);
+ }
+
+ /**
+ * Create a new MockClientDataRequest.
+ * @param portalContext the PortalContext that the request runs in
+ * @param portletContext the PortletContext that the request runs in
+ */
+ public MockClientDataRequest(PortalContext portalContext, PortletContext portletContext) {
+ super(portalContext, portletContext);
+ }
+
+
+ public void setContent(byte[] content) {
+ this.content = content;
+ }
+
+ public InputStream getPortletInputStream() throws IOException {
+ if (this.content != null) {
+ return new ByteArrayInputStream(this.content);
+ }
+ else {
+ return null;
+ }
+ }
+
+ public void setCharacterEncoding(String characterEncoding) {
+ this.characterEncoding = characterEncoding;
+ }
+
+ public BufferedReader getReader() throws UnsupportedEncodingException {
+ if (this.content != null) {
+ InputStream sourceStream = new ByteArrayInputStream(this.content);
+ Reader sourceReader = (this.characterEncoding != null) ?
+ new InputStreamReader(sourceStream, this.characterEncoding) : new InputStreamReader(sourceStream);
+ return new BufferedReader(sourceReader);
+ }
+ else {
+ return null;
+ }
+ }
+
+ public String getCharacterEncoding() {
+ return this.characterEncoding;
+ }
+
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ public String getContentType() {
+ return this.contentType;
+ }
+
+ public int getContentLength() {
+ return (this.content != null ? content.length : -1);
+ }
+
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ public String getMethod() {
+ return this.method;
+ }
+
+}
\ No newline at end of file
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockEvent.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..b58aced0ba5227c469f51e34530bd00b00290af8
--- /dev/null
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockEvent.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2002-2009 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.mock.web.portlet;
+
+import java.io.Serializable;
+import javax.portlet.Event;
+import javax.xml.namespace.QName;
+
+/**
+ * Mock implementation of the {@link javax.portlet.Event} interface.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ * @see MockEventRequest
+ */
+public class MockEvent implements Event {
+
+ private final QName name;
+
+ private final Serializable value;
+
+
+ /**
+ * Create a new MockEvent with the given name.
+ * @param name the name of the event
+ */
+ public MockEvent(QName name) {
+ this.name = name;
+ this.value = null;
+ }
+
+ /**
+ * Create a new MockEvent with the given name and value.
+ * @param name the name of the event
+ * @param value the associated payload of the event
+ */
+ public MockEvent(QName name, Serializable value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * Create a new MockEvent with the given name.
+ * @param name the name of the event
+ */
+ public MockEvent(String name) {
+ this.name = new QName(name);
+ this.value = null;
+ }
+
+ /**
+ * Create a new MockEvent with the given name and value.
+ * @param name the name of the event
+ * @param value the associated payload of the event
+ */
+ public MockEvent(String name, Serializable value) {
+ this.name = new QName(name);
+ this.value = value;
+ }
+
+
+ public QName getQName() {
+ return this.name;
+ }
+
+ public String getName() {
+ return this.name.getLocalPart();
+ }
+
+ public Serializable getValue() {
+ return this.value;
+ }
+
+}
\ No newline at end of file
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockEventRequest.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockEventRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2406f18d01ca83a574ab393635a4b4f11b264cc7
--- /dev/null
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockEventRequest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2002-2009 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.mock.web.portlet;
+
+import javax.portlet.Event;
+import javax.portlet.EventRequest;
+import javax.portlet.PortalContext;
+import javax.portlet.PortletContext;
+
+/**
+ * Mock implementation of the {@link javax.portlet.EventRequest} interface.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class MockEventRequest extends MockPortletRequest implements EventRequest {
+
+ private final Event event;
+
+ private String method;
+
+
+ /**
+ * Create a new MockEventRequest with a default {@link MockPortalContext}
+ * and a default {@link MockPortletContext}.
+ * @param event the event that this request wraps
+ * @see MockEvent
+ */
+ public MockEventRequest(Event event) {
+ super();
+ this.event = event;
+ }
+
+ /**
+ * Create a new MockEventRequest with a default {@link MockPortalContext}.
+ * @param event the event that this request wraps
+ * @param portletContext the PortletContext that the request runs in
+ * @see MockEvent
+ */
+ public MockEventRequest(Event event, PortletContext portletContext) {
+ super(portletContext);
+ this.event = event;
+ }
+
+ /**
+ * Create a new MockEventRequest.
+ * @param event the event that this request wraps
+ * @param portalContext the PortletContext that the request runs in
+ * @param portletContext the PortletContext that the request runs in
+ */
+ public MockEventRequest(Event event, PortalContext portalContext, PortletContext portletContext) {
+ super(portalContext, portletContext);
+ this.event = event;
+ }
+
+
+ @Override
+ protected String getLifecyclePhase() {
+ return EVENT_PHASE;
+ }
+
+ public Event getEvent() {
+ return this.event;
+ }
+
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ public String getMethod() {
+ return this.method;
+ }
+
+}
\ No newline at end of file
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockEventResponse.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockEventResponse.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa8dac4ce1e13fa50fe7b24d934ea1d353aab25f
--- /dev/null
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockEventResponse.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2002-2009 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.mock.web.portlet;
+
+import javax.portlet.EventResponse;
+import javax.portlet.EventRequest;
+
+/**
+ * Mock implementation of the {@link javax.portlet.EventResponse} interface.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class MockEventResponse extends MockStateAwareResponse implements EventResponse {
+
+ public void setRenderParameters(EventRequest request) {
+ setRenderParameters(request.getParameterMap());
+ }
+
+}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockMimeResponse.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockMimeResponse.java
new file mode 100644
index 0000000000000000000000000000000000000000..e606fc808d290fbb7320f93ca8b5870c200fc9c9
--- /dev/null
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockMimeResponse.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2002-2009 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.mock.web.portlet;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Locale;
+import javax.portlet.CacheControl;
+import javax.portlet.MimeResponse;
+import javax.portlet.PortalContext;
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletURL;
+import javax.portlet.ResourceURL;
+
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.util.WebUtils;
+
+/**
+ * Mock implementation of the {@link javax.portlet.MimeResponse} interface.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class MockMimeResponse extends MockPortletResponse implements MimeResponse {
+
+ private PortletRequest request;
+
+ private String contentType;
+
+ private String characterEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
+
+ private PrintWriter writer;
+
+ private Locale locale = Locale.getDefault();
+
+ private int bufferSize = 4096;
+
+ private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+ private final CacheControl cacheControl = new MockCacheControl();
+
+ private boolean committed;
+
+ private String includedUrl;
+
+ private String forwardedUrl;
+
+
+ /**
+ * Create a new MockMimeResponse with a default {@link MockPortalContext}.
+ * @see org.springframework.mock.web.portlet.MockPortalContext
+ */
+ public MockMimeResponse() {
+ super();
+ }
+
+ /**
+ * Create a new MockMimeResponse.
+ * @param portalContext the PortalContext defining the supported
+ * PortletModes and WindowStates
+ */
+ public MockMimeResponse(PortalContext portalContext) {
+ super(portalContext);
+ }
+
+ /**
+ * Create a new MockMimeResponse.
+ * @param portalContext the PortalContext defining the supported
+ * PortletModes and WindowStates
+ * @param request the corresponding render/resource request that this response
+ * is being generated for
+ */
+ public MockMimeResponse(PortalContext portalContext, PortletRequest request) {
+ super(portalContext);
+ this.request = request;
+ }
+
+
+ //---------------------------------------------------------------------
+ // RenderResponse methods
+ //---------------------------------------------------------------------
+
+ public void setContentType(String contentType) {
+ if (this.request != null) {
+ Enumeration supportedTypes = this.request.getResponseContentTypes();
+ if (!CollectionUtils.contains(supportedTypes, contentType)) {
+ throw new IllegalArgumentException("Content type [" + contentType + "] not in supported list: " +
+ Collections.list(supportedTypes));
+ }
+ }
+ this.contentType = contentType;
+ }
+
+ public String getContentType() {
+ return this.contentType;
+ }
+
+ public void setCharacterEncoding(String characterEncoding) {
+ this.characterEncoding = characterEncoding;
+ }
+
+ public String getCharacterEncoding() {
+ return this.characterEncoding;
+ }
+
+ public PrintWriter getWriter() throws UnsupportedEncodingException {
+ if (this.writer == null) {
+ Writer targetWriter = (this.characterEncoding != null
+ ? new OutputStreamWriter(this.outputStream, this.characterEncoding)
+ : new OutputStreamWriter(this.outputStream));
+ this.writer = new PrintWriter(targetWriter);
+ }
+ return this.writer;
+ }
+
+ public byte[] getContentAsByteArray() {
+ flushBuffer();
+ return this.outputStream.toByteArray();
+ }
+
+ public String getContentAsString() throws UnsupportedEncodingException {
+ flushBuffer();
+ return (this.characterEncoding != null)
+ ? this.outputStream.toString(this.characterEncoding)
+ : this.outputStream.toString();
+ }
+
+ public void setLocale(Locale locale) {
+ this.locale = locale;
+ }
+
+ public Locale getLocale() {
+ return this.locale;
+ }
+
+ public void setBufferSize(int bufferSize) {
+ this.bufferSize = bufferSize;
+ }
+
+ public int getBufferSize() {
+ return this.bufferSize;
+ }
+
+ public void flushBuffer() {
+ if (this.writer != null) {
+ this.writer.flush();
+ }
+ if (this.outputStream != null) {
+ try {
+ this.outputStream.flush();
+ }
+ catch (IOException ex) {
+ throw new IllegalStateException("Could not flush OutputStream: " + ex.getMessage());
+ }
+ }
+ this.committed = true;
+ }
+
+ public void resetBuffer() {
+ if (this.committed) {
+ throw new IllegalStateException("Cannot reset buffer - response is already committed");
+ }
+ this.outputStream.reset();
+ }
+
+ public void setCommitted(boolean committed) {
+ this.committed = committed;
+ }
+
+ public boolean isCommitted() {
+ return this.committed;
+ }
+
+ public void reset() {
+ resetBuffer();
+ this.characterEncoding = null;
+ this.contentType = null;
+ this.locale = null;
+ }
+
+ public OutputStream getPortletOutputStream() throws IOException {
+ return this.outputStream;
+ }
+
+ public PortletURL createRenderURL() {
+ return new MockPortletURL(getPortalContext(), MockPortletURL.URL_TYPE_RENDER);
+ }
+
+ public PortletURL createActionURL() {
+ return new MockPortletURL(getPortalContext(), MockPortletURL.URL_TYPE_ACTION);
+ }
+
+ public ResourceURL createResourceURL() {
+ return new MockResourceURL();
+ }
+
+ public CacheControl getCacheControl() {
+ return this.cacheControl;
+ }
+
+
+ //---------------------------------------------------------------------
+ // Methods for MockPortletRequestDispatcher
+ //---------------------------------------------------------------------
+
+ public void setIncludedUrl(String includedUrl) {
+ this.includedUrl = includedUrl;
+ }
+
+ public String getIncludedUrl() {
+ return this.includedUrl;
+ }
+
+ public void setForwardedUrl(String forwardedUrl) {
+ this.forwardedUrl = forwardedUrl;
+ }
+
+ public String getForwardedUrl() {
+ return this.forwardedUrl;
+ }
+
+}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockMultipartActionRequest.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockMultipartActionRequest.java
index cc2b2277cffbb8c3b5ad0ef1020c47c409a114d4..50d095d3e146a762f9ad3e6b58b012cb2db9fccc 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockMultipartActionRequest.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockMultipartActionRequest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortalContext.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortalContext.java
index 1a81847f978932b6f898fd55e98dc36f22346ee1..949d077b9a26fccaf50d0c35aed54f7e552d6bf2 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortalContext.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortalContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletConfig.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletConfig.java
index 249429e1a1307e76ff727d88cb65367e597c911e..d69e75d0c111de79bcee85f2ddd88c178728eed1 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletConfig.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -16,16 +16,19 @@
package org.springframework.mock.web.portlet;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
-import java.util.Properties;
import java.util.ResourceBundle;
-import java.util.LinkedHashMap;
-import java.util.Collections;
+import java.util.Set;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
import org.springframework.util.Assert;
@@ -46,6 +49,18 @@ public class MockPortletConfig implements PortletConfig {
private final Map initParameters = new LinkedHashMap();
+ private final Set publicRenderParameterNames = new LinkedHashSet();
+
+ private String defaultNamespace = XMLConstants.NULL_NS_URI;
+
+ private final Set publishingEventQNames = new LinkedHashSet();
+
+ private final Set processingEventQNames = new LinkedHashSet();
+
+ private final Set supportedLocales = new LinkedHashSet();
+
+ private final Map containerRuntimeOptions = new LinkedHashMap();
+
/**
* Create a new MockPortletConfig with a default {@link MockPortletContext}.
@@ -113,4 +128,56 @@ public class MockPortletConfig implements PortletConfig {
return Collections.enumeration(this.initParameters.keySet());
}
+ public void addPublicRenderParameterName(String name) {
+ this.publicRenderParameterNames.add(name);
+ }
+
+ public Enumeration getPublicRenderParameterNames() {
+ return Collections.enumeration(this.publicRenderParameterNames);
+ }
+
+ public void setDefaultNamespace(String defaultNamespace) {
+ this.defaultNamespace = defaultNamespace;
+ }
+
+ public String getDefaultNamespace() {
+ return this.defaultNamespace;
+ }
+
+ public void addPublishingEventQName(QName name) {
+ this.publishingEventQNames.add(name);
+ }
+
+ public Enumeration getPublishingEventQNames() {
+ return Collections.enumeration(this.publishingEventQNames);
+ }
+
+ public void addProcessingEventQName(QName name) {
+ this.processingEventQNames.add(name);
+ }
+
+ public Enumeration getProcessingEventQNames() {
+ return Collections.enumeration(this.processingEventQNames);
+ }
+
+ public void addSupportedLocale(Locale locale) {
+ this.supportedLocales.add(locale);
+ }
+
+ public Enumeration getSupportedLocales() {
+ return Collections.enumeration(this.supportedLocales);
+ }
+
+ public void addContainerRuntimeOption(String key, String value) {
+ this.containerRuntimeOptions.put(key, new String[] {value});
+ }
+
+ public void addContainerRuntimeOption(String key, String[] values) {
+ this.containerRuntimeOptions.put(key, values);
+ }
+
+ public Map getContainerRuntimeOptions() {
+ return Collections.unmodifiableMap(this.containerRuntimeOptions);
+ }
+
}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletContext.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletContext.java
index 336b21e95b4e30d6ae291a929974bd2777f7dc6b..f297a637de87ada1b7110cf427ba7ddfe1468659 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletContext.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -25,6 +25,7 @@ import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.portlet.PortletContext;
@@ -63,6 +64,8 @@ public class MockPortletContext implements PortletContext {
private String portletContextName = "MockPortletContext";
+ private Set containerRuntimeOptions = new LinkedHashSet();
+
/**
* Create a new MockPortletContext with no base path and a
@@ -248,7 +251,15 @@ public class MockPortletContext implements PortletContext {
}
public String getPortletContextName() {
- return portletContextName;
+ return this.portletContextName;
+ }
+
+ public void addContainerRuntimeOption(String key) {
+ this.containerRuntimeOptions.add(key);
+ }
+
+ public Enumeration getContainerRuntimeOptions() {
+ return Collections.enumeration(this.containerRuntimeOptions);
}
}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletPreferences.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletPreferences.java
index 122ead007e61d710884403375e066df3474bf5be..ec9574491cf76c4836c1980930b419ebee5a262c 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletPreferences.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletPreferences.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequest.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequest.java
index 84c8af733f330eeb1a92aa80e71f945dc189597e..92973e5f1afd4c514552571f395baeaaa709a7f3 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequest.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -33,6 +33,7 @@ import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;
import javax.portlet.WindowState;
+import javax.servlet.http.Cookie;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -90,6 +91,12 @@ public class MockPortletRequest implements PortletRequest {
private int serverPort = 80;
+ private String windowID;
+
+ private Cookie[] cookies;
+
+ private final Set publicParameterNames = new HashSet();
+
/**
* Create a new MockPortletRequest with a default {@link MockPortalContext}
@@ -120,6 +127,7 @@ public class MockPortletRequest implements PortletRequest {
this.portletContext = (portletContext != null ? portletContext : new MockPortletContext());
this.responseContentTypes.add("text/html");
this.locales.add(Locale.ENGLISH);
+ this.attributes.put(LIFECYCLE_PHASE, getLifecyclePhase());
}
@@ -127,6 +135,13 @@ public class MockPortletRequest implements PortletRequest {
// Lifecycle methods
//---------------------------------------------------------------------
+ /**
+ * Return the Portlet 2.0 lifecycle id for the current phase.
+ */
+ protected String getLifecyclePhase() {
+ return null;
+ }
+
/**
* Return whether this request is still active (that is, not completed yet).
*/
@@ -363,7 +378,7 @@ public class MockPortletRequest implements PortletRequest {
return this.parameters.get(name);
}
- public Map getParameterMap() {
+ public Map getParameterMap() {
return Collections.unmodifiableMap(this.parameters);
}
@@ -459,4 +474,54 @@ public class MockPortletRequest implements PortletRequest {
return this.serverPort;
}
+ public void setWindowID(String windowID) {
+ this.windowID = windowID;
+ }
+
+ public String getWindowID() {
+ return this.windowID;
+ }
+
+ public void setCookies(Cookie[] cookies) {
+ this.cookies = cookies;
+ }
+
+ public Cookie[] getCookies() {
+ return this.cookies;
+ }
+
+ public Map getPrivateParameterMap() {
+ if (!this.publicParameterNames.isEmpty()) {
+ Map filtered = new LinkedHashMap();
+ for (String key : this.parameters.keySet()) {
+ if (!this.publicParameterNames.contains(key)) {
+ filtered.put(key, this.parameters.get(key));
+ }
+ }
+ return filtered;
+ }
+ else {
+ return Collections.unmodifiableMap(this.parameters);
+ }
+ }
+
+ public Map getPublicParameterMap() {
+ if (!this.publicParameterNames.isEmpty()) {
+ Map filtered = new LinkedHashMap();
+ for (String key : this.parameters.keySet()) {
+ if (this.publicParameterNames.contains(key)) {
+ filtered.put(key, this.parameters.get(key));
+ }
+ }
+ return filtered;
+ }
+ else {
+ return Collections.emptyMap();
+ }
+ }
+
+ public void registerPublicParameter(String name) {
+ this.publicParameterNames.add(name);
+ }
+
}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequestDispatcher.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequestDispatcher.java
index 2703c1920c2e8c85fc64fb0300296e2a4e973145..ca8695f90e266f7e3d29d12406b7117658150682 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequestDispatcher.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletRequestDispatcher.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2006 the original author or authors.
+ * Copyright 2002-2009 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,10 @@
package org.springframework.mock.web.portlet;
import java.io.IOException;
-
import javax.portlet.PortletException;
+import javax.portlet.PortletRequest;
import javax.portlet.PortletRequestDispatcher;
+import javax.portlet.PortletResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
@@ -53,15 +54,31 @@ public class MockPortletRequestDispatcher implements PortletRequestDispatcher {
public void include(RenderRequest request, RenderResponse response) throws PortletException, IOException {
+ include((PortletRequest) request, (PortletResponse) response);
+ }
+
+ public void include(PortletRequest request, PortletResponse response) throws PortletException, IOException {
Assert.notNull(request, "Request must not be null");
Assert.notNull(response, "Response must not be null");
- if (!(response instanceof MockRenderResponse)) {
- throw new IllegalArgumentException("MockPortletRequestDispatcher requires MockRenderResponse");
+ if (!(response instanceof MockMimeResponse)) {
+ throw new IllegalArgumentException("MockPortletRequestDispatcher requires MockMimeResponse");
}
- ((MockRenderResponse) response).setIncludedUrl(this.url);
+ ((MockMimeResponse) response).setIncludedUrl(this.url);
if (logger.isDebugEnabled()) {
logger.debug("MockPortletRequestDispatcher: including URL [" + this.url + "]");
+ }
}
+
+ public void forward(PortletRequest request, PortletResponse response) throws PortletException, IOException {
+ Assert.notNull(request, "Request must not be null");
+ Assert.notNull(response, "Response must not be null");
+ if (!(response instanceof MockMimeResponse)) {
+ throw new IllegalArgumentException("MockPortletRequestDispatcher requires MockMimeResponse");
+ }
+ ((MockMimeResponse) response).setForwardedUrl(this.url);
+ if (logger.isDebugEnabled()) {
+ logger.debug("MockPortletRequestDispatcher: forwarding to URL [" + this.url + "]");
+ }
}
}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletResponse.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletResponse.java
index 2c94ddda4a5c281925c66e473bc1ba503e150ac6..b556209fcd37ba280acb190da10c260c28405145 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletResponse.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletResponse.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -16,12 +16,20 @@
package org.springframework.mock.web.portlet;
+import java.util.Collections;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
-
import javax.portlet.PortalContext;
import javax.portlet.PortletResponse;
+import javax.servlet.http.Cookie;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import org.springframework.util.Assert;
@@ -38,6 +46,14 @@ public class MockPortletResponse implements PortletResponse {
private final Map properties = new LinkedHashMap();
+ private String namespace = "";
+
+ private final Set cookies = new LinkedHashSet();
+
+ private final Map xmlProperties = new LinkedHashMap();
+
+ private Document xmlDocument;
+
/**
* Create a new MockPortletResponse with a default {@link MockPortalContext}.
@@ -88,8 +104,8 @@ public class MockPortletResponse implements PortletResponse {
this.properties.put(key, new String[] {value});
}
- public Set getPropertyNames() {
- return this.properties.keySet();
+ public Set getPropertyNames() {
+ return Collections.unmodifiableSet(this.properties.keySet());
}
public String getProperty(String key) {
@@ -107,4 +123,73 @@ public class MockPortletResponse implements PortletResponse {
return path;
}
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ public String getNamespace() {
+ return this.namespace;
+ }
+
+ public void addProperty(Cookie cookie) {
+ Assert.notNull(cookie, "Cookie must not be null");
+ this.cookies.add(cookie);
+ }
+
+ public Cookie[] getCookies() {
+ return this.cookies.toArray(new Cookie[this.cookies.size()]);
+ }
+
+ public Cookie getCookie(String name) {
+ Assert.notNull(name, "Cookie name must not be null");
+ for (Cookie cookie : this.cookies) {
+ if (name.equals(cookie.getName())) {
+ return cookie;
+ }
+ }
+ return null;
+ }
+
+ public void addProperty(String key, Element value) {
+ Assert.notNull(key, "Property key must not be null");
+ Element[] oldArr = this.xmlProperties.get(key);
+ if (oldArr != null) {
+ Element[] newArr = new Element[oldArr.length + 1];
+ System.arraycopy(oldArr, 0, newArr, 0, oldArr.length);
+ newArr[oldArr.length] = value;
+ this.xmlProperties.put(key, newArr);
+ }
+ else {
+ this.xmlProperties.put(key, new Element[] {value});
+ }
+ }
+
+
+ public Set getXmlPropertyNames() {
+ return Collections.unmodifiableSet(this.xmlProperties.keySet());
+ }
+
+ public Element getXmlProperty(String key) {
+ Assert.notNull(key, "Property key must not be null");
+ Element[] arr = this.xmlProperties.get(key);
+ return (arr != null && arr.length > 0 ? arr[0] : null);
+ }
+
+ public Element[] getXmlProperties(String key) {
+ Assert.notNull(key, "Property key must not be null");
+ return this.xmlProperties.get(key);
+ }
+
+ public Element createElement(String tagName) throws DOMException {
+ if (this.xmlDocument == null) {
+ try {
+ this.xmlDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+ }
+ catch (ParserConfigurationException ex) {
+ throw new DOMException(DOMException.INVALID_STATE_ERR, ex.toString());
+ }
+ }
+ return this.xmlDocument.createElement(tagName);
+ }
+
}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletSession.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletSession.java
index ab27defe000aa8a20572706b2ac06c49cf73f856..558961121d1877f80e2ece9eba06e14f4221a0b5 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletSession.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletSession.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -184,7 +184,23 @@ public class MockPortletSession implements PortletSession {
}
public PortletContext getPortletContext() {
- return portletContext;
+ return this.portletContext;
+ }
+
+ public Map getAttributeMap() {
+ return Collections.unmodifiableMap(this.portletAttributes);
+ }
+
+ public Map getAttributeMap(int scope) {
+ if (scope == PortletSession.PORTLET_SCOPE) {
+ return Collections.unmodifiableMap(this.portletAttributes);
+ }
+ else if (scope == PortletSession.APPLICATION_SCOPE) {
+ return Collections.unmodifiableMap(this.applicationAttributes);
+ }
+ else {
+ return Collections.emptyMap();
+ }
}
}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletURL.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletURL.java
index edf889cf93e083eed466ba9f982588660f32a68a..12abdf57c93165717064d85bdbeebb0b1625610b 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletURL.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockPortletURL.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -16,18 +16,10 @@
package org.springframework.mock.web.portlet;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
import java.util.Map;
-import java.util.Set;
-
import javax.portlet.PortalContext;
import javax.portlet.PortletMode;
import javax.portlet.PortletModeException;
-import javax.portlet.PortletSecurityException;
import javax.portlet.PortletURL;
import javax.portlet.WindowState;
import javax.portlet.WindowStateException;
@@ -42,14 +34,12 @@ import org.springframework.util.CollectionUtils;
* @author Juergen Hoeller
* @since 2.0
*/
-public class MockPortletURL implements PortletURL {
+public class MockPortletURL extends MockBaseURL implements PortletURL {
public static final String URL_TYPE_RENDER = "render";
public static final String URL_TYPE_ACTION = "action";
- private static final String ENCODING = "UTF-8";
-
private final PortalContext portalContext;
@@ -59,10 +49,6 @@ public class MockPortletURL implements PortletURL {
private PortletMode portletMode;
- private final Map parameters = new LinkedHashMap();
-
- private boolean secure = false;
-
/**
* Create a new MockPortletURL for the given URL type.
@@ -90,6 +76,10 @@ public class MockPortletURL implements PortletURL {
this.windowState = windowState;
}
+ public WindowState getWindowState() {
+ return this.windowState;
+ }
+
public void setPortletMode(PortletMode portletMode) throws PortletModeException {
if (!CollectionUtils.contains(this.portalContext.getSupportedPortletModes(), portletMode)) {
throw new PortletModeException("PortletMode not supported", portletMode);
@@ -97,77 +87,12 @@ public class MockPortletURL implements PortletURL {
this.portletMode = portletMode;
}
- public void setParameter(String key, String value) {
- Assert.notNull(key, "Parameter key must be null");
- Assert.notNull(value, "Parameter value must not be null");
- this.parameters.put(key, new String[] {value});
- }
-
- public void setParameter(String key, String[] values) {
- Assert.notNull(key, "Parameter key must be null");
- Assert.notNull(values, "Parameter values must not be null");
- this.parameters.put(key, values);
- }
-
- public void setParameters(Map parameters) {
- Assert.notNull(parameters, "Parameters Map must not be null");
- this.parameters.clear();
- for (Iterator it = parameters.entrySet().iterator(); it.hasNext();) {
- Map.Entry entry = (Map.Entry) it.next();
- Assert.isTrue(entry.getKey() instanceof String, "Key must be of type String");
- Assert.isTrue(entry.getValue() instanceof String[], "Value must be of type String[]");
- this.parameters.put((String) entry.getKey(), (String[]) entry.getValue());
- }
- }
-
- public Set getParameterNames() {
- return this.parameters.keySet();
- }
-
- public String getParameter(String name) {
- String[] arr = this.parameters.get(name);
- return (arr != null && arr.length > 0 ? arr[0] : null);
+ public PortletMode getPortletMode() {
+ return this.portletMode;
}
- public String[] getParameterValues(String name) {
- return this.parameters.get(name);
- }
-
- public Map getParameterMap() {
- return Collections.unmodifiableMap(this.parameters);
- }
-
- public void setSecure(boolean secure) throws PortletSecurityException {
- this.secure = secure;
- }
-
- public boolean isSecure() {
- return this.secure;
- }
-
-
- private String encodeParameter(String name, String value) {
- try {
- return URLEncoder.encode(name, ENCODING) + "=" + URLEncoder.encode(value, ENCODING);
- }
- catch (UnsupportedEncodingException ex) {
- return null;
- }
- }
-
- private String encodeParameter(String name, String[] values) {
- try {
- StringBuilder sb = new StringBuilder();
- for (int i = 0, n = values.length; i < n; i++) {
- sb.append((i > 0 ? ";" : "") +
- URLEncoder.encode(name, ENCODING) + "=" +
- URLEncoder.encode(values[i], ENCODING));
- }
- return sb.toString();
- }
- catch (UnsupportedEncodingException ex) {
- return null;
- }
+ public void removePublicRenderParameter(String name) {
+ this.parameters.remove(name);
}
@@ -183,7 +108,7 @@ public class MockPortletURL implements PortletURL {
for (Map.Entry entry : this.parameters.entrySet()) {
sb.append(";").append(encodeParameter("param_" + entry.getKey(), entry.getValue()));
}
- return (this.secure ? "https:" : "http:") +
+ return (isSecure() ? "https:" : "http:") +
"//localhost/mockportlet?" + sb.toString();
}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderRequest.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderRequest.java
index 5bb8c54e42d7966c0457c5a2fb4cf4c1f2f29d6c..d86ba7f2ad4443e538656b22d54c801b1fb0ed28 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderRequest.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderRequest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2007 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -20,6 +20,7 @@ import javax.portlet.PortalContext;
import javax.portlet.PortletContext;
import javax.portlet.PortletMode;
import javax.portlet.RenderRequest;
+import javax.portlet.WindowState;
/**
* Mock implementation of the {@link javax.portlet.RenderRequest} interface.
@@ -50,6 +51,18 @@ public class MockRenderRequest extends MockPortletRequest implements RenderReque
setPortletMode(portletMode);
}
+ /**
+ * Create a new MockRenderRequest with a default {@link MockPortalContext}
+ * and a default {@link MockPortletContext}.
+ * @param portletMode the mode that the portlet runs in
+ * @param windowState the window state to run the portlet in
+ */
+ public MockRenderRequest(PortletMode portletMode, WindowState windowState) {
+ super();
+ setPortletMode(portletMode);
+ setWindowState(windowState);
+ }
+
/**
* Create a new MockRenderRequest with a default {@link MockPortalContext}.
* @param portletContext the PortletContext that the request runs in
@@ -67,4 +80,14 @@ public class MockRenderRequest extends MockPortletRequest implements RenderReque
super(portalContext, portletContext);
}
+
+ @Override
+ protected String getLifecyclePhase() {
+ return RENDER_PHASE;
+ }
+
+ public String getETag() {
+ return getProperty(RenderRequest.ETAG);
+ }
+
}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderResponse.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderResponse.java
index c63e9a4459996cb32bb96bb051e307410bde3279..a2feeb3726df68b589e951cc7d09818fabf4cd4f 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderResponse.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockRenderResponse.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2006 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -16,21 +16,12 @@
package org.springframework.mock.web.portlet;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.util.Locale;
-
+import java.util.Collection;
import javax.portlet.PortalContext;
-import javax.portlet.PortletURL;
+import javax.portlet.PortletMode;
+import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
-import org.springframework.web.util.WebUtils;
-
/**
* Mock implementation of the {@link javax.portlet.RenderResponse} interface.
*
@@ -38,27 +29,11 @@ import org.springframework.web.util.WebUtils;
* @author Juergen Hoeller
* @since 2.0
*/
-public class MockRenderResponse extends MockPortletResponse implements RenderResponse {
-
- private String contentType;
-
- private String namespace = "MockPortlet";
+public class MockRenderResponse extends MockMimeResponse implements RenderResponse {
private String title;
- private String characterEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
-
- private PrintWriter writer;
-
- private Locale locale = Locale.getDefault();
-
- private int bufferSize = 4096;
-
- private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-
- private boolean committed;
-
- private String includedUrl;
+ private Collection nextPossiblePortletModes;
/**
@@ -78,139 +53,36 @@ public class MockRenderResponse extends MockPortletResponse implements RenderRes
super(portalContext);
}
+ /**
+ * Create a new MockRenderResponse.
+ * @param portalContext the PortalContext defining the supported
+ * PortletModes and WindowStates
+ * @param request the corresponding render request that this response
+ * is generated for
+ */
+ public MockRenderResponse(PortalContext portalContext, RenderRequest request) {
+ super(portalContext, request);
+ }
+
//---------------------------------------------------------------------
// RenderResponse methods
//---------------------------------------------------------------------
- public String getContentType() {
- return this.contentType;
- }
-
- public PortletURL createRenderURL() {
- PortletURL url = new MockPortletURL(getPortalContext(), MockPortletURL.URL_TYPE_RENDER);
- return url;
- }
-
- public PortletURL createActionURL() {
- PortletURL url = new MockPortletURL(getPortalContext(), MockPortletURL.URL_TYPE_ACTION);
- return url;
- }
-
- public String getNamespace() {
- return this.namespace;
- }
-
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
- return title;
- }
-
- public void setContentType(String contentType) {
- this.contentType = contentType;
- }
-
- public void setCharacterEncoding(String characterEncoding) {
- this.characterEncoding = characterEncoding;
- }
-
- public String getCharacterEncoding() {
- return this.characterEncoding;
+ return this.title;
}
- public PrintWriter getWriter() throws UnsupportedEncodingException {
- if (this.writer == null) {
- Writer targetWriter = (this.characterEncoding != null
- ? new OutputStreamWriter(this.outputStream, this.characterEncoding)
- : new OutputStreamWriter(this.outputStream));
- this.writer = new PrintWriter(targetWriter);
- }
- return this.writer;
- }
-
- public byte[] getContentAsByteArray() {
- flushBuffer();
- return this.outputStream.toByteArray();
- }
-
- public String getContentAsString() throws UnsupportedEncodingException {
- flushBuffer();
- return (this.characterEncoding != null)
- ? this.outputStream.toString(this.characterEncoding)
- : this.outputStream.toString();
- }
-
- public void setLocale(Locale locale) {
- this.locale = locale;
- }
-
- public Locale getLocale() {
- return this.locale;
- }
-
- public void setBufferSize(int bufferSize) {
- this.bufferSize = bufferSize;
- }
-
- public int getBufferSize() {
- return this.bufferSize;
- }
-
- public void flushBuffer() {
- if (this.writer != null) {
- this.writer.flush();
- }
- if (this.outputStream != null) {
- try {
- this.outputStream.flush();
- }
- catch (IOException ex) {
- throw new IllegalStateException("Could not flush OutputStream: " + ex.getMessage());
- }
- }
- this.committed = true;
- }
-
- public void resetBuffer() {
- if (this.committed) {
- throw new IllegalStateException("Cannot reset buffer - response is already committed");
- }
- this.outputStream.reset();
- }
-
- public void setCommitted(boolean committed) {
- this.committed = committed;
- }
-
- public boolean isCommitted() {
- return this.committed;
- }
-
- public void reset() {
- resetBuffer();
- this.characterEncoding = null;
- this.contentType = null;
- this.locale = null;
- }
-
- public OutputStream getPortletOutputStream() throws IOException {
- return this.outputStream;
- }
-
-
- //---------------------------------------------------------------------
- // Methods for MockPortletRequestDispatcher
- //---------------------------------------------------------------------
-
- public void setIncludedUrl(String includedUrl) {
- this.includedUrl = includedUrl;
+ public void setNextPossiblePortletModes(Collection portletModes) {
+ this.nextPossiblePortletModes = portletModes;
}
- public String getIncludedUrl() {
- return includedUrl;
+ public Collection getNextPossiblePortletModes() {
+ return this.nextPossiblePortletModes;
}
}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockResourceRequest.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockResourceRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7cce4ba3c6d09dceb6a8f98b1b968c56c9aab15c
--- /dev/null
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockResourceRequest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2002-2009 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.mock.web.portlet;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import javax.portlet.PortalContext;
+import javax.portlet.PortletContext;
+import javax.portlet.RenderRequest;
+import javax.portlet.ResourceRequest;
+
+/**
+ * Mock implementation of the {@link javax.portlet.ResourceRequest} interface.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class MockResourceRequest extends MockClientDataRequest implements ResourceRequest {
+
+ private String resourceID;
+
+ private String cacheability;
+
+ private final Map privateRenderParameterMap = new LinkedHashMap();
+
+
+ /**
+ * Create a new MockResourceRequest with a default {@link MockPortalContext}
+ * and a default {@link MockPortletContext}.
+ * @see org.springframework.mock.web.portlet.MockPortalContext
+ * @see org.springframework.mock.web.portlet.MockPortletContext
+ */
+ public MockResourceRequest() {
+ super();
+ }
+
+ /**
+ * Create a new MockResourceRequest with a default {@link MockPortalContext}
+ * and a default {@link MockPortletContext}.
+ * @param resourceID the resource id for this request
+ */
+ public MockResourceRequest(String resourceID) {
+ super();
+ this.resourceID = resourceID;
+ }
+
+ /**
+ * Create a new MockResourceRequest with a default {@link MockPortalContext}
+ * and a default {@link MockPortletContext}.
+ * @param url the resource URL for this request
+ */
+ public MockResourceRequest(MockResourceURL url) {
+ super();
+ this.resourceID = url.getResourceID();
+ this.cacheability = url.getCacheability();
+ }
+
+ /**
+ * Create a new MockResourceRequest with a default {@link MockPortalContext}.
+ * @param portletContext the PortletContext that the request runs in
+ */
+ public MockResourceRequest(PortletContext portletContext) {
+ super(portletContext);
+ }
+
+ /**
+ * Create a new MockResourceRequest.
+ * @param portalContext the PortalContext that the request runs in
+ * @param portletContext the PortletContext that the request runs in
+ */
+ public MockResourceRequest(PortalContext portalContext, PortletContext portletContext) {
+ super(portalContext, portletContext);
+ }
+
+
+ @Override
+ protected String getLifecyclePhase() {
+ return RESOURCE_PHASE;
+ }
+
+ public void setResourceID(String resourceID) {
+ this.resourceID = resourceID;
+ }
+
+ public String getResourceID() {
+ return this.resourceID;
+ }
+
+ public void setCacheability(String cacheLevel) {
+ this.cacheability = cacheLevel;
+ }
+
+ public String getCacheability() {
+ return this.cacheability;
+ }
+
+ public String getETag() {
+ return getProperty(RenderRequest.ETAG);
+ }
+
+ public void addPrivateRenderParameter(String key, String value) {
+ this.privateRenderParameterMap.put(key, new String[] {value});
+ }
+
+ public void addPrivateRenderParameter(String key, String[] values) {
+ this.privateRenderParameterMap.put(key, values);
+ }
+
+ public Map getPrivateRenderParameterMap() {
+ return Collections.unmodifiableMap(this.privateRenderParameterMap);
+ }
+
+}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockResourceResponse.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockResourceResponse.java
new file mode 100644
index 0000000000000000000000000000000000000000..297a19682eac9ee5341cfd5936e19ea48cd1d1ec
--- /dev/null
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockResourceResponse.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2002-2009 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.mock.web.portlet;
+
+import javax.portlet.ResourceResponse;
+
+/**
+ * Mock implementation of the {@link javax.portlet.ResourceResponse} interface.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class MockResourceResponse extends MockMimeResponse implements ResourceResponse {
+
+ private int contentLength = 0;
+
+
+ public void setContentLength(int len) {
+ this.contentLength = len;
+ }
+
+ public int getContentLength() {
+ return this.contentLength;
+ }
+
+}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockResourceURL.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockResourceURL.java
new file mode 100644
index 0000000000000000000000000000000000000000..cce36b18d55265b385eed162ce5207e2022250c0
--- /dev/null
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockResourceURL.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2002-2009 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.mock.web.portlet;
+
+import java.util.Map;
+import javax.portlet.ResourceURL;
+
+/**
+ * Mock implementation of the {@link javax.portlet.ResourceURL} interface.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class MockResourceURL extends MockBaseURL implements ResourceURL {
+
+ private String resourceID;
+
+ private String cacheability;
+
+
+ //---------------------------------------------------------------------
+ // ResourceURL methods
+ //---------------------------------------------------------------------
+
+ public void setResourceID(String resourceID) {
+ this.resourceID = resourceID;
+ }
+
+ public String getResourceID() {
+ return this.resourceID;
+ }
+
+ public void setCacheability(String cacheLevel) {
+ this.cacheability = cacheLevel;
+ }
+
+ public String getCacheability() {
+ return this.cacheability;
+ }
+
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(encodeParameter("resourceID", this.resourceID));
+ if (this.cacheability != null) {
+ sb.append(";").append(encodeParameter("cacheability", this.cacheability));
+ }
+ for (Map.Entry entry : this.parameters.entrySet()) {
+ sb.append(";").append(encodeParameter("param_" + entry.getKey(), entry.getValue()));
+ }
+ return (isSecure() ? "https:" : "http:") +
+ "//localhost/mockportlet?" + sb.toString();
+ }
+
+}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockStateAwareResponse.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockStateAwareResponse.java
new file mode 100644
index 0000000000000000000000000000000000000000..131110971d4aca76997c04993d56a552a46f0fc2
--- /dev/null
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockStateAwareResponse.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2002-2009 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.mock.web.portlet;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import javax.portlet.ActionResponse;
+import javax.portlet.PortalContext;
+import javax.portlet.PortletMode;
+import javax.portlet.PortletModeException;
+import javax.portlet.WindowState;
+import javax.portlet.WindowStateException;
+import javax.portlet.StateAwareResponse;
+import javax.xml.namespace.QName;
+
+import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Mock implementation of the {@link javax.portlet.StateAwareResponse} interface.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class MockStateAwareResponse extends MockPortletResponse implements StateAwareResponse {
+
+ private WindowState windowState;
+
+ private PortletMode portletMode;
+
+ private final Map renderParameters = new LinkedHashMap();
+
+ private final Map events = new HashMap();
+
+
+ /**
+ * Create a new MockActionResponse with a default {@link MockPortalContext}.
+ * @see org.springframework.mock.web.portlet.MockPortalContext
+ */
+ public MockStateAwareResponse() {
+ super();
+ }
+
+ /**
+ * Create a new MockActionResponse.
+ * @param portalContext the PortalContext defining the supported
+ * PortletModes and WindowStates
+ */
+ public MockStateAwareResponse(PortalContext portalContext) {
+ super(portalContext);
+ }
+
+
+ public void setWindowState(WindowState windowState) throws WindowStateException {
+ if (!CollectionUtils.contains(getPortalContext().getSupportedWindowStates(), windowState)) {
+ throw new WindowStateException("WindowState not supported", windowState);
+ }
+ this.windowState = windowState;
+ }
+
+ public WindowState getWindowState() {
+ return this.windowState;
+ }
+
+ public void setPortletMode(PortletMode portletMode) throws PortletModeException {
+ if (!CollectionUtils.contains(getPortalContext().getSupportedPortletModes(), portletMode)) {
+ throw new PortletModeException("PortletMode not supported", portletMode);
+ }
+ this.portletMode = portletMode;
+ }
+
+ public PortletMode getPortletMode() {
+ return this.portletMode;
+ }
+
+ public void setRenderParameters(Map parameters) {
+ Assert.notNull(parameters, "Parameters Map must not be null");
+ this.renderParameters.clear();
+ this.renderParameters.putAll(parameters);
+ }
+
+ public void setRenderParameter(String key, String value) {
+ Assert.notNull(key, "Parameter key must not be null");
+ Assert.notNull(value, "Parameter value must not be null");
+ this.renderParameters.put(key, new String[] {value});
+ }
+
+ public void setRenderParameter(String key, String[] values) {
+ Assert.notNull(key, "Parameter key must not be null");
+ Assert.notNull(values, "Parameter values must not be null");
+ this.renderParameters.put(key, values);
+ }
+
+ public String getRenderParameter(String key) {
+ Assert.notNull(key, "Parameter key must not be null");
+ String[] arr = this.renderParameters.get(key);
+ return (arr != null && arr.length > 0 ? arr[0] : null);
+ }
+
+ public String[] getRenderParameterValues(String key) {
+ Assert.notNull(key, "Parameter key must not be null");
+ return this.renderParameters.get(key);
+ }
+
+ public Iterator getRenderParameterNames() {
+ return this.renderParameters.keySet().iterator();
+ }
+
+ public Map getRenderParameterMap() {
+ return Collections.unmodifiableMap(this.renderParameters);
+ }
+
+ public void removePublicRenderParameter(String name) {
+ this.renderParameters.remove(name);
+ }
+
+ public void setEvent(QName name, Serializable value) {
+ this.events.put(name, value);
+ }
+
+ public void setEvent(String name, Serializable value) {
+ this.events.put(new QName(name), value);
+ }
+
+ public Iterator getEventNames() {
+ return this.events.keySet().iterator();
+ }
+
+ public Serializable getEvent(QName name) {
+ return this.events.get(name);
+ }
+
+ public Serializable getEvent(String name) {
+ return this.events.get(new QName(name));
+ }
+
+}
\ No newline at end of file
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/ComplexPortletApplicationContext.java b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/ComplexPortletApplicationContext.java
index f7aa8c1aad8d5a5da9bdb4aa14abdebfeb80b9f9..a7299bee7ef1981bc93266dcdf774679b1df8397 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/ComplexPortletApplicationContext.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/ComplexPortletApplicationContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2006 the original author or authors.
+ * Copyright 2002-2008 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.
@@ -22,15 +22,18 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
+import javax.portlet.EventRequest;
+import javax.portlet.EventResponse;
import javax.portlet.Portlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
@@ -50,6 +53,7 @@ import org.springframework.web.multipart.MultipartException;
import org.springframework.web.portlet.bind.PortletRequestBindingException;
import org.springframework.web.portlet.context.PortletRequestHandledEvent;
import org.springframework.web.portlet.context.StaticPortletApplicationContext;
+import org.springframework.web.portlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.portlet.handler.ParameterHandlerMapping;
import org.springframework.web.portlet.handler.ParameterMappingInterceptor;
import org.springframework.web.portlet.handler.PortletModeHandlerMapping;
@@ -352,17 +356,18 @@ public class ComplexPortletApplicationContext extends StaticPortletApplicationCo
((MyHandler) delegate).doSomething(request);
return null;
}
- }
-
-
- public static class MyHandlerInterceptor1 implements HandlerInterceptor {
- public boolean preHandleAction(ActionRequest request, ActionResponse response, Object handler) {
- return true;
+ public ModelAndView handleResource(ResourceRequest request, ResourceResponse response, Object handler)
+ throws Exception {
+ return null;
}
- public void afterActionCompletion(ActionRequest request, ActionResponse response, Object handler, Exception ex) {
+ public void handleEvent(EventRequest request, EventResponse response, Object handler) throws Exception {
}
+ }
+
+
+ public static class MyHandlerInterceptor1 extends HandlerInterceptorAdapter {
public boolean preHandleRender(RenderRequest request, RenderResponse response, Object handler)
throws PortletException {
@@ -398,14 +403,7 @@ public class ComplexPortletApplicationContext extends StaticPortletApplicationCo
}
- public static class MyHandlerInterceptor2 implements HandlerInterceptor {
-
- public boolean preHandleAction(ActionRequest request, ActionResponse response, Object handler) {
- return true;
- }
-
- public void afterActionCompletion(ActionRequest request, ActionResponse response, Object handler, Exception ex) {
- }
+ public static class MyHandlerInterceptor2 extends HandlerInterceptorAdapter {
public boolean preHandleRender(RenderRequest request, RenderResponse response, Object handler)
throws PortletException {
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/mvc/annotation/Portlet20AnnotationControllerTests.java b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/mvc/annotation/Portlet20AnnotationControllerTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..fae16d091b6638f31ac275ff69683b220acedead
--- /dev/null
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/mvc/annotation/Portlet20AnnotationControllerTests.java
@@ -0,0 +1,923 @@
+/*
+ * Copyright 2002-2009 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.web.portlet.mvc.annotation;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import javax.portlet.ActionRequest;
+import javax.portlet.ActionResponse;
+import javax.portlet.EventResponse;
+import javax.portlet.MimeResponse;
+import javax.portlet.PortletContext;
+import javax.portlet.PortletMode;
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletSession;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+import javax.portlet.StateAwareResponse;
+import javax.portlet.UnavailableException;
+import javax.portlet.WindowState;
+
+import junit.framework.TestCase;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.DerivedTestBean;
+import org.springframework.beans.ITestBean;
+import org.springframework.beans.TestBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.propertyeditors.CustomDateEditor;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigUtils;
+import org.springframework.core.MethodParameter;
+import org.springframework.mock.web.portlet.MockActionRequest;
+import org.springframework.mock.web.portlet.MockActionResponse;
+import org.springframework.mock.web.portlet.MockEvent;
+import org.springframework.mock.web.portlet.MockEventRequest;
+import org.springframework.mock.web.portlet.MockEventResponse;
+import org.springframework.mock.web.portlet.MockPortletConfig;
+import org.springframework.mock.web.portlet.MockPortletContext;
+import org.springframework.mock.web.portlet.MockRenderRequest;
+import org.springframework.mock.web.portlet.MockRenderResponse;
+import org.springframework.mock.web.portlet.MockResourceRequest;
+import org.springframework.mock.web.portlet.MockResourceResponse;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ExtendedModelMap;
+import org.springframework.ui.Model;
+import org.springframework.ui.ModelMap;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.Errors;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.InitBinder;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.support.WebArgumentResolver;
+import org.springframework.web.bind.support.WebBindingInitializer;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.context.support.GenericWebApplicationContext;
+import org.springframework.web.portlet.DispatcherPortlet;
+import org.springframework.web.portlet.ModelAndView;
+import org.springframework.web.portlet.bind.annotation.ActionMapping;
+import org.springframework.web.portlet.bind.annotation.EventMapping;
+import org.springframework.web.portlet.bind.annotation.RenderMapping;
+import org.springframework.web.portlet.bind.annotation.ResourceMapping;
+import org.springframework.web.portlet.context.StaticPortletApplicationContext;
+import org.springframework.web.portlet.mvc.AbstractController;
+
+/**
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class Portlet20AnnotationControllerTests extends TestCase {
+
+ public void testStandardHandleMethod() throws Exception {
+ DispatcherPortlet portlet = new DispatcherPortlet() {
+ protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException {
+ GenericWebApplicationContext wac = new GenericWebApplicationContext();
+ wac.registerBeanDefinition("controller", new RootBeanDefinition(MyController.class));
+ wac.refresh();
+ return wac;
+ }
+ };
+ portlet.init(new MockPortletConfig());
+
+ MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW);
+ MockRenderResponse response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("test", response.getContentAsString());
+ }
+
+ public void testAdaptedHandleMethods() throws Exception {
+ doTestAdaptedHandleMethods(MyAdaptedController.class);
+ }
+
+ public void testAdaptedHandleMethods2() throws Exception {
+ doTestAdaptedHandleMethods(MyAdaptedController2.class);
+ }
+
+ public void testAdaptedHandleMethods3() throws Exception {
+ doTestAdaptedHandleMethods(MyAdaptedController3.class);
+ }
+
+ public void doTestAdaptedHandleMethods(final Class controllerClass) throws Exception {
+ DispatcherPortlet portlet = new DispatcherPortlet() {
+ protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException {
+ GenericWebApplicationContext wac = new GenericWebApplicationContext();
+ wac.registerBeanDefinition("controller", new RootBeanDefinition(controllerClass));
+ wac.refresh();
+ return wac;
+ }
+ };
+ portlet.init(new MockPortletConfig());
+
+ MockActionRequest actionRequest = new MockActionRequest(PortletMode.VIEW);
+ MockActionResponse actionResponse = new MockActionResponse();
+ portlet.processAction(actionRequest, actionResponse);
+ assertEquals("value", actionResponse.getRenderParameter("test"));
+
+ MockRenderRequest request = new MockRenderRequest(PortletMode.EDIT);
+ request.addParameter("param1", "value1");
+ request.addParameter("param2", "2");
+ MockRenderResponse response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("test-value1-2", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.HELP);
+ request.addParameter("name", "name1");
+ request.addParameter("age", "2");
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("test-name1-2", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.VIEW);
+ request.addParameter("name", "name1");
+ request.addParameter("age", "value2");
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("test-name1-typeMismatch", response.getContentAsString());
+ }
+
+ public void testFormController() throws Exception {
+ DispatcherPortlet portlet = new DispatcherPortlet() {
+ protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException {
+ GenericWebApplicationContext wac = new GenericWebApplicationContext();
+ wac.registerBeanDefinition("controller", new RootBeanDefinition(MyFormController.class));
+ wac.refresh();
+ return wac;
+ }
+ protected void render(ModelAndView mv, PortletRequest request, MimeResponse response) throws Exception {
+ new TestView().render(mv.getViewName(), mv.getModel(), request, response);
+ }
+ };
+ portlet.init(new MockPortletConfig());
+
+ MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW);
+ request.addParameter("name", "name1");
+ request.addParameter("age", "value2");
+ MockRenderResponse response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString());
+ }
+
+ public void testModelFormController() throws Exception {
+ DispatcherPortlet portlet = new DispatcherPortlet() {
+ protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException {
+ GenericWebApplicationContext wac = new GenericWebApplicationContext();
+ wac.registerBeanDefinition("controller", new RootBeanDefinition(MyModelFormController.class));
+ wac.refresh();
+ return wac;
+ }
+ protected void render(ModelAndView mv, PortletRequest request, MimeResponse response) throws Exception {
+ new TestView().render(mv.getViewName(), mv.getModel(), request, response);
+ }
+ };
+ portlet.init(new MockPortletConfig());
+
+ MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW);
+ request.addParameter("name", "name1");
+ request.addParameter("age", "value2");
+ MockRenderResponse response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString());
+ }
+
+ public void testCommandProvidingFormController() throws Exception {
+ DispatcherPortlet portlet = new DispatcherPortlet() {
+ protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException {
+ GenericWebApplicationContext wac = new GenericWebApplicationContext();
+ wac.registerBeanDefinition("controller", new RootBeanDefinition(MyCommandProvidingFormController.class));
+ RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
+ adapterDef.getPropertyValues().addPropertyValue("webBindingInitializer", new MyWebBindingInitializer());
+ wac.registerBeanDefinition("handlerAdapter", adapterDef);
+ wac.refresh();
+ return wac;
+ }
+ protected void render(ModelAndView mv, PortletRequest request, MimeResponse response) throws Exception {
+ new TestView().render(mv.getViewName(), mv.getModel(), request, response);
+ }
+ };
+ portlet.init(new MockPortletConfig());
+
+ MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW);
+ request.addParameter("defaultName", "myDefaultName");
+ request.addParameter("age", "value2");
+ request.addParameter("date", "2007-10-02");
+ MockRenderResponse response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString());
+ }
+
+ public void testTypedCommandProvidingFormController() throws Exception {
+ DispatcherPortlet portlet = new DispatcherPortlet() {
+ protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException {
+ GenericWebApplicationContext wac = new GenericWebApplicationContext();
+ wac.registerBeanDefinition("controller", new RootBeanDefinition(MyTypedCommandProvidingFormController.class));
+ wac.registerBeanDefinition("controller2", new RootBeanDefinition(MyOtherTypedCommandProvidingFormController.class));
+ RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
+ adapterDef.getPropertyValues().addPropertyValue("webBindingInitializer", new MyWebBindingInitializer());
+ adapterDef.getPropertyValues().addPropertyValue("customArgumentResolver", new MySpecialArgumentResolver());
+ wac.registerBeanDefinition("handlerAdapter", adapterDef);
+ wac.refresh();
+ return wac;
+ }
+ protected void render(ModelAndView mv, PortletRequest request, MimeResponse response) throws Exception {
+ new TestView().render(mv.getViewName(), mv.getModel(), request, response);
+ }
+ };
+ portlet.init(new MockPortletConfig());
+
+ MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW);
+ request.addParameter("myParam", "myValue");
+ request.addParameter("defaultName", "10");
+ request.addParameter("age", "value2");
+ request.addParameter("date", "2007-10-02");
+ MockRenderResponse response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myView-Integer:10-typeMismatch-tb1-myOriginalValue", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.VIEW);
+ request.addParameter("myParam", "myOtherValue");
+ request.addParameter("defaultName", "10");
+ request.addParameter("age", "value2");
+ request.addParameter("date", "2007-10-02");
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myOtherView-Integer:10-typeMismatch-tb1-myOriginalValue", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.EDIT);
+ request.addParameter("myParam", "myValue");
+ request.addParameter("defaultName", "10");
+ request.addParameter("age", "value2");
+ request.addParameter("date", "2007-10-02");
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myView-myName-typeMismatch-tb1-myOriginalValue", response.getContentAsString());
+ }
+
+ public void testBinderInitializingCommandProvidingFormController() throws Exception {
+ DispatcherPortlet portlet = new DispatcherPortlet() {
+ protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException {
+ GenericWebApplicationContext wac = new GenericWebApplicationContext();
+ wac.registerBeanDefinition("controller", new RootBeanDefinition(MyBinderInitializingCommandProvidingFormController.class));
+ wac.refresh();
+ return wac;
+ }
+ protected void render(ModelAndView mv, PortletRequest request, MimeResponse response) throws Exception {
+ new TestView().render(mv.getViewName(), mv.getModel(), request, response);
+ }
+ };
+ portlet.init(new MockPortletConfig());
+
+ MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW);
+ request.addParameter("defaultName", "myDefaultName");
+ request.addParameter("age", "value2");
+ request.addParameter("date", "2007-10-02");
+ MockRenderResponse response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString());
+ }
+
+ public void testSpecificBinderInitializingCommandProvidingFormController() throws Exception {
+ DispatcherPortlet portlet = new DispatcherPortlet() {
+ protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException {
+ StaticPortletApplicationContext wac = new StaticPortletApplicationContext();
+ wac.registerBeanDefinition("controller", new RootBeanDefinition(MySpecificBinderInitializingCommandProvidingFormController.class));
+ wac.refresh();
+ return wac;
+ }
+ protected void render(ModelAndView mv, PortletRequest request, MimeResponse response) throws Exception {
+ new TestView().render(mv.getViewName(), mv.getModel(), request, response);
+ }
+ };
+ portlet.init(new MockPortletConfig());
+
+ MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW);
+ request.addParameter("defaultName", "myDefaultName");
+ request.addParameter("age", "value2");
+ request.addParameter("date", "2007-10-02");
+ MockRenderResponse response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString());
+ }
+
+ public void testParameterDispatchingController() throws Exception {
+ DispatcherPortlet portlet = new DispatcherPortlet() {
+ protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException {
+ StaticPortletApplicationContext wac = new StaticPortletApplicationContext();
+ wac.setPortletContext(new MockPortletContext());
+ RootBeanDefinition bd = new RootBeanDefinition(MyParameterDispatchingController.class);
+ bd.setScope(WebApplicationContext.SCOPE_REQUEST);
+ wac.registerBeanDefinition("controller", bd);
+ AnnotationConfigUtils.registerAnnotationConfigProcessors(wac);
+ wac.refresh();
+ return wac;
+ }
+ };
+ portlet.init(new MockPortletConfig());
+
+ MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW);
+ MockRenderResponse response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myView", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.VIEW);
+ request.addParameter("view", "other");
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myOtherView", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.VIEW);
+ request.addParameter("view", "my");
+ request.addParameter("lang", "de");
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myLangView", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.VIEW);
+ request.addParameter("surprise", "!");
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("mySurpriseView", response.getContentAsString());
+ }
+
+ public void testTypeLevelParameterDispatchingController() throws Exception {
+ DispatcherPortlet portlet = new DispatcherPortlet() {
+ protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException {
+ StaticPortletApplicationContext wac = new StaticPortletApplicationContext();
+ wac.setPortletContext(new MockPortletContext());
+ RootBeanDefinition bd = new RootBeanDefinition(MyTypeLevelParameterDispatchingController.class);
+ bd.setScope(WebApplicationContext.SCOPE_REQUEST);
+ wac.registerBeanDefinition("controller", bd);
+ RootBeanDefinition bd2 = new RootBeanDefinition(MySpecialParameterDispatchingController.class);
+ bd2.setScope(WebApplicationContext.SCOPE_REQUEST);
+ wac.registerBeanDefinition("controller2", bd2);
+ RootBeanDefinition bd3 = new RootBeanDefinition(MyOtherSpecialParameterDispatchingController.class);
+ bd3.setScope(WebApplicationContext.SCOPE_REQUEST);
+ wac.registerBeanDefinition("controller3", bd3);
+ RootBeanDefinition bd4 = new RootBeanDefinition(MyParameterDispatchingController.class);
+ bd4.setScope(WebApplicationContext.SCOPE_REQUEST);
+ wac.registerBeanDefinition("controller4", bd4);
+ AnnotationConfigUtils.registerAnnotationConfigProcessors(wac);
+ wac.refresh();
+ return wac;
+ }
+ };
+ portlet.init(new MockPortletConfig());
+
+ MockRenderRequest request = new MockRenderRequest(PortletMode.HELP);
+ MockRenderResponse response = new MockRenderResponse();
+ try {
+ portlet.render(request, response);
+ fail("Should have thrown UnavailableException");
+ }
+ catch (UnavailableException ex) {
+ // expected
+ }
+
+ request = new MockRenderRequest(PortletMode.EDIT);
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myDefaultView", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.EDIT);
+ request.addParameter("myParam", "myValue");
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myView", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.EDIT);
+ request.addParameter("myParam", "mySpecialValue");
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("mySpecialView", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.EDIT);
+ request.addParameter("myParam", "myOtherSpecialValue");
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myOtherSpecialView", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.VIEW);
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myView", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.EDIT);
+ request.addParameter("myParam", "myValue");
+ request.addParameter("view", "other");
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myOtherView", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.EDIT);
+ request.addParameter("myParam", "myValue");
+ request.addParameter("view", "my");
+ request.addParameter("lang", "de");
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myLangView", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.EDIT);
+ request.addParameter("myParam", "myValue");
+ request.addParameter("surprise", "!");
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("mySurpriseView", response.getContentAsString());
+ }
+
+ public void testPortlet20DispatchingController() throws Exception {
+ DispatcherPortlet portlet = new DispatcherPortlet() {
+ protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException {
+ StaticPortletApplicationContext wac = new StaticPortletApplicationContext();
+ wac.setPortletContext(new MockPortletContext());
+ RootBeanDefinition bd = new RootBeanDefinition(MyPortlet20DispatchingController.class);
+ bd.setScope(WebApplicationContext.SCOPE_REQUEST);
+ wac.registerBeanDefinition("controller", bd);
+ AnnotationConfigUtils.registerAnnotationConfigProcessors(wac);
+ wac.refresh();
+ return wac;
+ }
+ };
+ portlet.init(new MockPortletConfig());
+
+ MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW);
+ MockRenderResponse response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myView", response.getContentAsString());
+
+ MockActionRequest actionRequest = new MockActionRequest("this");
+ MockActionResponse actionResponse = new MockActionResponse();
+ portlet.processAction(actionRequest, actionResponse);
+
+ request = new MockRenderRequest(PortletMode.VIEW, WindowState.MAXIMIZED);
+ request.setParameters(actionResponse.getRenderParameterMap());
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myLargeView-value", response.getContentAsString());
+
+ actionRequest = new MockActionRequest("that");
+ actionResponse = new MockActionResponse();
+ portlet.processAction(actionRequest, actionResponse);
+
+ request = new MockRenderRequest(PortletMode.VIEW, WindowState.MAXIMIZED);
+ request.setParameters(actionResponse.getRenderParameterMap());
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myLargeView-value2", response.getContentAsString());
+
+ MockEventRequest eventRequest = new MockEventRequest(new MockEvent("event1"));
+ MockEventResponse eventResponse = new MockEventResponse();
+ portlet.processEvent(eventRequest, eventResponse);
+
+ request = new MockRenderRequest(PortletMode.VIEW, WindowState.MAXIMIZED);
+ request.setParameters(eventResponse.getRenderParameterMap());
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myLargeView-value3", response.getContentAsString());
+
+ eventRequest = new MockEventRequest(new MockEvent("event2"));
+ eventResponse = new MockEventResponse();
+ portlet.processEvent(eventRequest, eventResponse);
+
+ request = new MockRenderRequest(PortletMode.VIEW, WindowState.MAXIMIZED);
+ request.setParameters(eventResponse.getRenderParameterMap());
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myLargeView-value4", response.getContentAsString());
+
+ request = new MockRenderRequest(PortletMode.VIEW, WindowState.NORMAL);
+ request.setParameters(actionResponse.getRenderParameterMap());
+ response = new MockRenderResponse();
+ portlet.render(request, response);
+ assertEquals("myView", response.getContentAsString());
+
+ MockResourceRequest resourceRequest = new MockResourceRequest("resource1");
+ MockResourceResponse resourceResponse = new MockResourceResponse();
+ portlet.serveResource(resourceRequest, resourceResponse);
+ assertEquals("myResource", resourceResponse.getContentAsString());
+
+ resourceRequest = new MockResourceRequest("resource2");
+ resourceResponse = new MockResourceResponse();
+ portlet.serveResource(resourceRequest, resourceResponse);
+ assertEquals("myDefaultResource", resourceResponse.getContentAsString());
+ }
+
+
+ @RequestMapping("VIEW")
+ private static class MyController extends AbstractController {
+
+ protected ModelAndView handleRenderRequestInternal(RenderRequest request, RenderResponse response) throws Exception {
+ response.getWriter().write("test");
+ return null;
+ }
+ }
+
+
+ @Controller
+ private static class MyAdaptedController {
+
+ @RequestMapping("VIEW")
+ @ActionMapping
+ public void myHandle(ActionRequest request, ActionResponse response) throws IOException {
+ response.setRenderParameter("test", "value");
+ }
+
+ @RequestMapping("EDIT")
+ @RenderMapping
+ public void myHandle(@RequestParam("param1")String p1, @RequestParam("param2")int p2, RenderResponse response) throws IOException {
+ response.getWriter().write("test-" + p1 + "-" + p2);
+ }
+
+ @RequestMapping("HELP")
+ @RenderMapping
+ public void myHandle(TestBean tb, RenderResponse response) throws IOException {
+ response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge());
+ }
+
+ @RequestMapping("VIEW")
+ @RenderMapping
+ public void myHandle(TestBean tb, Errors errors, RenderResponse response) throws IOException {
+ response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode());
+ }
+ }
+
+
+ @Controller
+ private static class MyAdaptedController2 {
+
+ @RequestMapping("VIEW")
+ @ActionMapping
+ public void myHandle(ActionRequest request, ActionResponse response) throws IOException {
+ response.setRenderParameter("test", "value");
+ }
+
+ @RequestMapping("EDIT")
+ @RenderMapping
+ public void myHandle(@RequestParam("param1")String p1, int param2, RenderResponse response) throws IOException {
+ response.getWriter().write("test-" + p1 + "-" + param2);
+ }
+
+ @RequestMapping("HELP")
+ @RenderMapping
+ public void myHandle(TestBean tb, RenderResponse response) throws IOException {
+ response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge());
+ }
+
+ @RequestMapping("VIEW")
+ @RenderMapping
+ public void myHandle(TestBean tb, Errors errors, RenderResponse response) throws IOException {
+ response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode());
+ }
+ }
+
+
+ @Controller
+ @RequestMapping({"VIEW", "EDIT", "HELP"})
+ private static class MyAdaptedController3 {
+
+ @ActionMapping
+ public void myHandle(ActionRequest request, ActionResponse response) {
+ response.setRenderParameter("test", "value");
+ }
+
+ @RequestMapping("EDIT")
+ @RenderMapping
+ public void myHandle(@RequestParam("param1")String p1, @RequestParam("param2")int p2, RenderResponse response) throws IOException {
+ response.getWriter().write("test-" + p1 + "-" + p2);
+ }
+
+ @RequestMapping("HELP")
+ @RenderMapping
+ public void myHandle(TestBean tb, RenderResponse response) throws IOException {
+ response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge());
+ }
+
+ @RenderMapping
+ public void myHandle(TestBean tb, Errors errors, RenderResponse response) throws IOException {
+ response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode());
+ }
+ }
+
+
+ @Controller
+ private static class MyFormController {
+
+ @ModelAttribute("testBeanList")
+ public List getTestBeans() {
+ List list = new LinkedList();
+ list.add(new TestBean("tb1"));
+ list.add(new TestBean("tb2"));
+ return list;
+ }
+
+ @RequestMapping("VIEW")
+ @RenderMapping
+ public String myHandle(@ModelAttribute("myCommand")TestBean tb, BindingResult errors, ModelMap model) {
+ if (!model.containsKey("myKey")) {
+ model.addAttribute("myKey", "myValue");
+ }
+ return "myView";
+ }
+ }
+
+
+ @Controller
+ private static class MyModelFormController {
+
+ @ModelAttribute
+ public List getTestBeans() {
+ List list = new LinkedList();
+ list.add(new TestBean("tb1"));
+ list.add(new TestBean("tb2"));
+ return list;
+ }
+
+ @RequestMapping("VIEW")
+ @RenderMapping
+ public String myHandle(@ModelAttribute("myCommand")TestBean tb, BindingResult errors, Model model) {
+ if (!model.containsAttribute("myKey")) {
+ model.addAttribute("myKey", "myValue");
+ }
+ return "myView";
+ }
+ }
+
+
+ @Controller
+ private static class MyCommandProvidingFormController extends MyFormController {
+
+ @ModelAttribute("myCommand")
+ private TestBean createTestBean(
+ @RequestParam T defaultName, Map model, @RequestParam Date date) {
+ model.put("myKey", "myOriginalValue");
+ return new TestBean(defaultName.getClass().getSimpleName() + ":" + defaultName.toString());
+ }
+
+ @RequestMapping("VIEW")
+ @RenderMapping
+ public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, ModelMap model) {
+ if (!model.containsKey("myKey")) {
+ model.addAttribute("myKey", "myValue");
+ }
+ return "myView";
+ }
+
+ @RequestMapping("EDIT")
+ @RenderMapping
+ public String myOtherHandle(TB tb, BindingResult errors, ExtendedModelMap model, MySpecialArg arg) {
+ TestBean tbReal = (TestBean) tb;
+ tbReal.setName("myName");
+ assertTrue(model.get("ITestBean") instanceof DerivedTestBean);
+ assertNotNull(arg);
+ return super.myHandle(tbReal, errors, model);
+ }
+
+ @ModelAttribute
+ protected TB2 getModelAttr() {
+ return (TB2) new DerivedTestBean();
+ }
+ }
+
+
+ private static class MySpecialArg {
+
+ public MySpecialArg(String value) {
+ }
+ }
+
+
+ @Controller
+ @RequestMapping(params = "myParam=myValue")
+ private static class MyTypedCommandProvidingFormController
+ extends MyCommandProvidingFormController {
+
+ }
+
+
+ @Controller
+ @RequestMapping(params = "myParam=myOtherValue")
+ private static class MyOtherTypedCommandProvidingFormController
+ extends MyCommandProvidingFormController {
+
+ @RequestMapping("VIEW")
+ @RenderMapping
+ public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, ModelMap model) {
+ if (!model.containsKey("myKey")) {
+ model.addAttribute("myKey", "myValue");
+ }
+ return "myOtherView";
+ }
+ }
+
+
+ @Controller
+ private static class MyBinderInitializingCommandProvidingFormController extends MyCommandProvidingFormController {
+
+ @InitBinder
+ private void initBinder(WebDataBinder binder) {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ dateFormat.setLenient(false);
+ binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
+ }
+ }
+
+
+ @Controller
+ private static class MySpecificBinderInitializingCommandProvidingFormController extends MyCommandProvidingFormController {
+
+ @SuppressWarnings("unused")
+ @InitBinder({"myCommand", "date"})
+ private void initBinder(WebDataBinder binder) {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ dateFormat.setLenient(false);
+ binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
+ }
+ }
+
+
+ private static class MyWebBindingInitializer implements WebBindingInitializer {
+
+ public void initBinder(WebDataBinder binder, WebRequest request) {
+ assertNotNull(request.getLocale());
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ dateFormat.setLenient(false);
+ binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
+ }
+ }
+
+
+ private static class MySpecialArgumentResolver implements WebArgumentResolver {
+
+ public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) {
+ if (methodParameter.getParameterType().equals(MySpecialArg.class)) {
+ return new MySpecialArg("myValue");
+ }
+ return UNRESOLVED;
+ }
+ }
+
+
+ @Controller
+ @RequestMapping("VIEW")
+ private static class MyParameterDispatchingController {
+
+ @Autowired
+ private PortletContext portletContext;
+
+ @Autowired
+ private PortletSession session;
+
+ @Autowired
+ private PortletRequest request;
+
+ @RenderMapping
+ public void myHandle(RenderResponse response) throws IOException {
+ if (this.portletContext == null || this.session == null || this.request == null) {
+ throw new IllegalStateException();
+ }
+ response.getWriter().write("myView");
+ }
+
+ @RenderMapping(params = {"view", "!lang"})
+ public void myOtherHandle(RenderResponse response) throws IOException {
+ response.getWriter().write("myOtherView");
+ }
+
+ @RenderMapping(params = {"view=my", "lang=de"})
+ public void myLangHandle(RenderResponse response) throws IOException {
+ response.getWriter().write("myLangView");
+ }
+
+ @RenderMapping(params = "surprise")
+ public void mySurpriseHandle(RenderResponse response) throws IOException {
+ response.getWriter().write("mySurpriseView");
+ }
+ }
+
+
+ @Controller
+ @RequestMapping(value = "EDIT", params = "myParam=myValue")
+ private static class MyTypeLevelParameterDispatchingController extends MyParameterDispatchingController {
+
+ }
+
+
+ @Controller
+ @RequestMapping("EDIT")
+ private static class MySpecialParameterDispatchingController {
+
+ @RenderMapping(params = "myParam=mySpecialValue")
+ public void myHandle(RenderResponse response) throws IOException {
+ response.getWriter().write("mySpecialView");
+ }
+
+ @RenderMapping
+ public void myDefaultHandle(RenderResponse response) throws IOException {
+ response.getWriter().write("myDefaultView");
+ }
+ }
+
+
+ @Controller
+ @RequestMapping("EDIT")
+ private static class MyOtherSpecialParameterDispatchingController {
+
+ @RenderMapping(params = "myParam=myOtherSpecialValue")
+ public void myHandle(RenderResponse response) throws IOException {
+ response.getWriter().write("myOtherSpecialView");
+ }
+ }
+
+
+ @Controller
+ @RequestMapping("VIEW")
+ private static class MyPortlet20DispatchingController {
+
+ @ActionMapping("this")
+ public void myHandle(StateAwareResponse response) {
+ response.setRenderParameter("test", "value");
+ }
+
+ @ActionMapping("that")
+ public void myHandle2(StateAwareResponse response) {
+ response.setRenderParameter("test", "value2");
+ }
+
+ @EventMapping("event1")
+ public void myHandle(EventResponse response) throws IOException {
+ response.setRenderParameter("test", "value3");
+ }
+
+ @EventMapping("event2")
+ public void myHandle2(EventResponse response) throws IOException {
+ response.setRenderParameter("test", "value4");
+ }
+
+ @RenderMapping("MAXIMIZED")
+ public void myHandle(Writer writer, @RequestParam("test") String renderParam) throws IOException {
+ writer.write("myLargeView-" + renderParam);
+ }
+
+ @RenderMapping
+ public void myDefaultHandle(Writer writer) throws IOException {
+ writer.write("myView");
+ }
+
+ @ResourceMapping("resource1")
+ public void myResource(Writer writer) throws IOException {
+ writer.write("myResource");
+ }
+
+ @ResourceMapping
+ public void myDefaultResource(Writer writer) throws IOException {
+ writer.write("myDefaultResource");
+ }
+ }
+
+
+ private static class TestView {
+
+ public void render(String viewName, Map model, PortletRequest request, MimeResponse response) throws Exception {
+ TestBean tb = (TestBean) model.get("testBean");
+ if (tb == null) {
+ tb = (TestBean) model.get("myCommand");
+ }
+ if (tb.getName().endsWith("myDefaultName")) {
+ assertTrue(tb.getDate().getYear() == 107);
+ }
+ Errors errors = (Errors) model.get(BindingResult.MODEL_KEY_PREFIX + "testBean");
+ if (errors == null) {
+ errors = (Errors) model.get(BindingResult.MODEL_KEY_PREFIX + "myCommand");
+ }
+ if (errors.hasFieldErrors("date")) {
+ throw new IllegalStateException();
+ }
+ List testBeans = (List) model.get("testBeanList");
+ response.getWriter().write(viewName + "-" + tb.getName() + "-" + errors.getFieldError("age").getCode() +
+ "-" + testBeans.get(0).getName() + "-" + model.get("myKey"));
+ }
+ }
+
+}
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/mvc/annotation/PortletAnnotationControllerTests.java b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/mvc/annotation/PortletAnnotationControllerTests.java
index 714f250dcf958f4674ee5ac7b2311f9566f02fd2..fe2ab448c53d08e2a976507042320d9883d2435f 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/mvc/annotation/PortletAnnotationControllerTests.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/mvc/annotation/PortletAnnotationControllerTests.java
@@ -22,9 +22,9 @@ import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
+import javax.portlet.MimeResponse;
import javax.portlet.PortletContext;
import javax.portlet.PortletMode;
import javax.portlet.PortletRequest;
@@ -154,8 +154,7 @@ public class PortletAnnotationControllerTests extends TestCase {
wac.refresh();
return wac;
}
-
- protected void render(ModelAndView mv, RenderRequest request, RenderResponse response) throws Exception {
+ protected void render(ModelAndView mv, PortletRequest request, MimeResponse response) throws Exception {
new TestView().render(mv.getViewName(), mv.getModel(), request, response);
}
};
@@ -177,8 +176,7 @@ public class PortletAnnotationControllerTests extends TestCase {
wac.refresh();
return wac;
}
-
- protected void render(ModelAndView mv, RenderRequest request, RenderResponse response) throws Exception {
+ protected void render(ModelAndView mv, PortletRequest request, MimeResponse response) throws Exception {
new TestView().render(mv.getViewName(), mv.getModel(), request, response);
}
};
@@ -203,8 +201,7 @@ public class PortletAnnotationControllerTests extends TestCase {
wac.refresh();
return wac;
}
-
- protected void render(ModelAndView mv, RenderRequest request, RenderResponse response) throws Exception {
+ protected void render(ModelAndView mv, PortletRequest request, MimeResponse response) throws Exception {
new TestView().render(mv.getViewName(), mv.getModel(), request, response);
}
};
@@ -232,7 +229,7 @@ public class PortletAnnotationControllerTests extends TestCase {
wac.refresh();
return wac;
}
- protected void render(ModelAndView mv, RenderRequest request, RenderResponse response) throws Exception {
+ protected void render(ModelAndView mv, PortletRequest request, MimeResponse response) throws Exception {
new TestView().render(mv.getViewName(), mv.getModel(), request, response);
}
};
@@ -274,8 +271,7 @@ public class PortletAnnotationControllerTests extends TestCase {
wac.refresh();
return wac;
}
-
- protected void render(ModelAndView mv, RenderRequest request, RenderResponse response) throws Exception {
+ protected void render(ModelAndView mv, PortletRequest request, MimeResponse response) throws Exception {
new TestView().render(mv.getViewName(), mv.getModel(), request, response);
}
};
@@ -298,8 +294,7 @@ public class PortletAnnotationControllerTests extends TestCase {
wac.refresh();
return wac;
}
-
- protected void render(ModelAndView mv, RenderRequest request, RenderResponse response) throws Exception {
+ protected void render(ModelAndView mv, PortletRequest request, MimeResponse response) throws Exception {
new TestView().render(mv.getViewName(), mv.getModel(), request, response);
}
};
@@ -753,7 +748,7 @@ public class PortletAnnotationControllerTests extends TestCase {
private static class TestView {
- public void render(String viewName, Map model, RenderRequest request, RenderResponse response) throws Exception {
+ public void render(String viewName, Map model, PortletRequest request, MimeResponse response) throws Exception {
TestBean tb = (TestBean) model.get("testBean");
if (tb == null) {
tb = (TestBean) model.get("myCommand");
diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/util/PortletUtilsTests.java b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/util/PortletUtilsTests.java
index cb2089844f12127aa300d928b4892ae580c5b68c..d37bb93da3a5f4050371ad8707342facfa05caa2 100644
--- a/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/util/PortletUtilsTests.java
+++ b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/util/PortletUtilsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2006 the original author or authors.
+ * Copyright 2002-2009 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.
@@ -16,21 +16,19 @@
package org.springframework.web.portlet.util;
-import static org.easymock.EasyMock.*;
-import static org.junit.Assert.*;
-
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Collections;
-import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
-
import javax.portlet.PortletContext;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
import org.junit.Test;
+
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.mock.web.portlet.MockActionRequest;
@@ -41,8 +39,6 @@ import org.springframework.mock.web.portlet.MockPortletSession;
import org.springframework.web.util.WebUtils;
/**
- * Unit tests for {@link PortletUtils}.
- *
* @author Rick Evans
* @author Chris Beams
*/
@@ -303,27 +299,14 @@ public final class PortletUtilsTests {
PortletUtils.exposeRequestAttributes(new MockPortletRequest(), null);
}
-
- @SuppressWarnings("unchecked")
- @Test(expected=ClassCastException.class)
- public void testExposeRequestAttributesWithAttributesMapContainingBadKeyType() throws Exception {
- MockPortletRequest request = new MockPortletRequest();
- Map attributes = new HashMap