提交 464c7eed 编写于 作者: J Juergen Hoeller

updated Spring Portlet MVC to Portlet API 2.0

上级 76888e24
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/> <classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.web"/> <classpathentry combineaccessrules="false" kind="src" path="/org.springframework.web"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.web.servlet"/> <classpathentry combineaccessrules="false" kind="src" path="/org.springframework.web.servlet"/>
<classpathentry kind="var" path="IVY_CACHE/javax.portlet/com.springsource.javax.portlet/1.0.0/com.springsource.javax.portlet-1.0.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/javax.portlet/com.springsource.javax.portlet/2.0.0/com.springsource.javax.portlet-2.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.fileupload/1.2.0/com.springsource.org.apache.commons.fileupload-1.2.0.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.fileupload/1.2.0/com.springsource.org.apache.commons.fileupload-sources-1.2.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.fileupload/1.2.0/com.springsource.org.apache.commons.fileupload-1.2.0.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.fileupload/1.2.0/com.springsource.org.apache.commons.fileupload-sources-1.2.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.5.0/com.springsource.org.junit-4.5.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.5.0/com.springsource.org.junit-sources-4.5.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.5.0/com.springsource.org.junit-4.5.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.5.0/com.springsource.org.junit-sources-4.5.0.jar"/>
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
<dependencies> <dependencies>
<dependency org="javax.el" name="com.springsource.javax.el" rev="1.0.0" conf="provided->compile"/> <dependency org="javax.el" name="com.springsource.javax.el" rev="1.0.0" conf="provided->compile"/>
<dependency org="javax.portlet" name="com.springsource.javax.portlet" rev="1.0.0" conf="provided->compile"/> <dependency org="javax.portlet" name="com.springsource.javax.portlet" rev="2.0.0" conf="provided->compile"/>
<dependency org="javax.servlet" name="com.springsource.javax.servlet" rev="2.5.0" conf="compile->compile"/> <dependency org="javax.servlet" name="com.springsource.javax.servlet" rev="2.5.0" conf="compile->compile"/>
<dependency org="javax.servlet" name="com.springsource.javax.servlet.jsp" rev="2.1.0" conf="test->compile"/> <dependency org="javax.servlet" name="com.springsource.javax.servlet.jsp" rev="2.1.0" conf="test->compile"/>
<dependency org="javax.servlet" name="com.springsource.javax.servlet.jsp.jstl" rev="1.1.2" conf="test->compile"/> <dependency org="javax.servlet" name="com.springsource.javax.servlet.jsp.jstl" rev="1.1.2" conf="test->compile"/>
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -19,14 +19,17 @@ package org.springframework.web.portlet; ...@@ -19,14 +19,17 @@ package org.springframework.web.portlet;
import java.io.IOException; import java.io.IOException;
import java.security.Principal; import java.security.Principal;
import java.util.Map; import java.util.Map;
import javax.portlet.ActionRequest; import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse; import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.PortletException; import javax.portlet.PortletException;
import javax.portlet.PortletRequest; import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse; import javax.portlet.PortletResponse;
import javax.portlet.RenderRequest; import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse; import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
...@@ -37,8 +40,14 @@ import org.springframework.context.ApplicationListener; ...@@ -37,8 +40,14 @@ import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.SourceFilteringListener; 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.ConfigurablePortletApplicationContext;
import org.springframework.web.portlet.context.PortletApplicationContextUtils; 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.PortletRequestHandledEvent;
import org.springframework.web.portlet.context.XmlPortletApplicationContext; import org.springframework.web.portlet.context.XmlPortletApplicationContext;
...@@ -136,6 +145,9 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App ...@@ -136,6 +145,9 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
/** Should we publish a PortletRequestHandledEvent at the end of each request? */ /** Should we publish a PortletRequestHandledEvent at the end of each request? */
private boolean publishEvents = true; 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 */ /** USER_INFO attributes that may contain the username of the current user */
private String[] userinfoUsernameAttributes = DEFAULT_USERINFO_ATTRIBUTE_NAMES; private String[] userinfoUsernameAttributes = DEFAULT_USERINFO_ATTRIBUTE_NAMES;
...@@ -205,13 +217,6 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App ...@@ -205,13 +217,6 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
this.publishContext = publishContext; 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 * 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 * 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 ...@@ -223,11 +228,19 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
} }
/** /**
* Return whether this portlet should publish a PortletRequestHandledEvent at the end * Set whether to expose the LocaleContext and RequestAttributes as inheritable
* of each request. * for child threads (using an {@link java.lang.InheritableThreadLocal}).
* <p>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).
* <p><b>WARNING:</b> 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() { public void setThreadContextInheritable(boolean threadContextInheritable) {
return this.publishEvents; this.threadContextInheritable = threadContextInheritable;
} }
/** /**
...@@ -239,15 +252,6 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App ...@@ -239,15 +252,6 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
this.userinfoUsernameAttributes = userinfoUsernameAttributes; 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 * Overridden method of GenericPortletBean, invoked after any bean properties
...@@ -297,7 +301,7 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App ...@@ -297,7 +301,7 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
onRefresh(pac); onRefresh(pac);
} }
if (isPublishContext()) { if (this.publishContext) {
// publish the context as a portlet context attribute // publish the context as a portlet context attribute
String attName = getPortletContextAttributeName(); String attName = getPortletContextAttributeName();
getPortletContext().setAttribute(attName, pac); getPortletContext().setAttribute(attName, pac);
...@@ -447,25 +451,39 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App ...@@ -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 @Override
protected final void doDispatch(RenderRequest request, RenderResponse response) public final void processAction(ActionRequest request, ActionResponse response)
throws PortletException, IOException { throws PortletException, IOException {
processRequest(request, response); processRequest(request, response);
} }
/** /**
* Delegate action requests to processRequest/doActionService. * Delegate render requests to processRequest/doRenderService.
*/ */
@Override @Override
public final void processAction(ActionRequest request, ActionResponse response) protected final void doDispatch(RenderRequest request, RenderResponse response)
throws PortletException, IOException { throws PortletException, IOException {
processRequest(request, response); 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. * Process this request, publishing an event regardless of the outcome.
* The actual event handling is performed by the abstract * The actual event handling is performed by the abstract
...@@ -479,13 +497,36 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App ...@@ -479,13 +497,36 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
Throwable failureCause = null; 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 { try {
if (request instanceof ActionRequest) { String phase = (String) request.getAttribute(PortletRequest.LIFECYCLE_PHASE);
if (PortletRequest.ACTION_PHASE.equals(phase)) {
doActionService((ActionRequest) request, (ActionResponse) response); doActionService((ActionRequest) request, (ActionResponse) response);
} }
else { else if (PortletRequest.RENDER_PHASE.equals(phase)) {
doRenderService((RenderRequest) request, (RenderResponse) response); 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) { catch (PortletException ex) {
failureCause = ex; failureCause = ex;
...@@ -501,13 +542,23 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App ...@@ -501,13 +542,23 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
} }
finally { 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) { if (failureCause != null) {
logger.error("Could not complete request", failureCause); logger.error("Could not complete request", failureCause);
} }
else { else {
logger.debug("Successfully completed request"); logger.debug("Successfully completed request");
} }
if (isPublishEvents()) { if (this.publishEvents) {
// Whether or not we succeeded, publish an event. // Whether or not we succeeded, publish an event.
long processingTime = System.currentTimeMillis() - startTime; long processingTime = System.currentTimeMillis() - startTime;
this.portletApplicationContext.publishEvent( this.portletApplicationContext.publishEvent(
...@@ -520,6 +571,16 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App ...@@ -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. * Determine the username for the given request.
* <p>The default implementation first tries the UserPrincipal. * <p>The default implementation first tries the UserPrincipal.
...@@ -560,6 +621,21 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App ...@@ -560,6 +621,21 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
return null; return null;
} }
/**
* Subclasses must implement this method to do the work of action request handling.
* <p>The contract is essentially the same as that for the <code>processAction</code>
* method of GenericPortlet.
* <p>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. * Subclasses must implement this method to do the work of render request handling.
* <p>The contract is essentially the same as that for the <code>doDispatch</code> * <p>The contract is essentially the same as that for the <code>doDispatch</code>
...@@ -575,17 +651,31 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App ...@@ -575,17 +651,31 @@ public abstract class FrameworkPortlet extends GenericPortletBean implements App
throws Exception; throws Exception;
/** /**
* Subclasses must implement this method to do the work of action request handling. * Subclasses must implement this method to do the work of resource request handling.
* <p>The contract is essentially the same as that for the <code>processAction</code> * <p>The contract is essentially the same as that for the <code>serveResource</code>
* method of GenericPortlet. * method of GenericPortlet.
* <p>This class intercepts calls to ensure that exception handling and * <p>This class intercepts calls to ensure that exception handling and
* event publication takes place. * event publication takes place.
* @param request current action request * @param request current resource request
* @param response current action response * @param response current resource response
* @throws Exception in case of any kind of processing failure * @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.
* <p>The contract is essentially the same as that for the <code>processEvent</code>
* method of GenericPortlet.
* <p>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; throws Exception;
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -18,8 +18,12 @@ package org.springframework.web.portlet; ...@@ -18,8 +18,12 @@ package org.springframework.web.portlet;
import javax.portlet.ActionRequest; import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse; import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.RenderRequest; import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse; import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
/** /**
* Portlet MVC framework SPI interface, allowing parameterization of core MVC workflow. * Portlet MVC framework SPI interface, allowing parameterization of core MVC workflow.
...@@ -67,6 +71,7 @@ public interface HandlerAdapter { ...@@ -67,6 +71,7 @@ public interface HandlerAdapter {
* to the <code>supports</code> method of this interface, which must have * to the <code>supports</code> method of this interface, which must have
* returned true. * returned true.
* @throws Exception in case of errors * @throws Exception in case of errors
* @see javax.portlet.Portlet#processAction
*/ */
void handleAction(ActionRequest request, ActionResponse response, Object handler) throws Exception; void handleAction(ActionRequest request, ActionResponse response, Object handler) throws Exception;
...@@ -81,7 +86,36 @@ public interface HandlerAdapter { ...@@ -81,7 +86,36 @@ public interface HandlerAdapter {
* @throws Exception in case of errors * @throws Exception in case of errors
* @return ModelAndView object with the name of the view and the required * @return ModelAndView object with the name of the view and the required
* model data, or <code>null</code> if the request has been handled directly * model data, or <code>null</code> if the request has been handled directly
* @see javax.portlet.Portlet#render
*/ */
ModelAndView handleRender(RenderRequest request, RenderResponse response, Object handler) throws Exception; 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 <code>supports</code> method of this interface, which must have
* returned <code>true</code>.
* @throws Exception in case of errors
* @return ModelAndView object with the name of the view and the required
* model data, or <code>null</code> 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 <code>supports</code> 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;
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
...@@ -18,6 +18,8 @@ package org.springframework.web.portlet; ...@@ -18,6 +18,8 @@ package org.springframework.web.portlet;
import javax.portlet.RenderRequest; import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse; import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
/** /**
* Interface to be implemented by objects than can resolve exceptions thrown * Interface to be implemented by objects than can resolve exceptions thrown
...@@ -47,4 +49,17 @@ public interface HandlerExceptionResolver { ...@@ -47,4 +49,17 @@ public interface HandlerExceptionResolver {
ModelAndView resolveException( ModelAndView resolveException(
RenderRequest request, RenderResponse response, Object handler, Exception ex); 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);
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -20,6 +20,10 @@ import javax.portlet.ActionRequest; ...@@ -20,6 +20,10 @@ import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse; import javax.portlet.ActionResponse;
import javax.portlet.RenderRequest; import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse; 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. * Workflow interface that allows for customized handler execution chains.
...@@ -130,7 +134,7 @@ public interface HandlerInterceptor { ...@@ -130,7 +134,7 @@ public interface HandlerInterceptor {
* @throws Exception in case of errors * @throws Exception in case of errors
*/ */
boolean preHandleAction(ActionRequest request, ActionResponse response, Object handler) boolean preHandleAction(ActionRequest request, ActionResponse response, Object handler)
throws Exception; throws Exception;
/** /**
* Callback after completion of request processing in the action phase, that is, * Callback after completion of request processing in the action phase, that is,
...@@ -149,7 +153,7 @@ public interface HandlerInterceptor { ...@@ -149,7 +153,7 @@ public interface HandlerInterceptor {
*/ */
void afterActionCompletion( void afterActionCompletion(
ActionRequest request, ActionResponse response, Object handler, Exception ex) ActionRequest request, ActionResponse response, Object handler, Exception ex)
throws Exception; throws Exception;
/** /**
* Intercept the execution of a handler in the render phase. * Intercept the execution of a handler in the render phase.
...@@ -169,7 +173,7 @@ public interface HandlerInterceptor { ...@@ -169,7 +173,7 @@ public interface HandlerInterceptor {
* @throws Exception in case of errors * @throws Exception in case of errors
*/ */
boolean preHandleRender(RenderRequest request, RenderResponse response, Object handler) boolean preHandleRender(RenderRequest request, RenderResponse response, Object handler)
throws Exception; throws Exception;
/** /**
* Intercept the execution of a handler in the render phase. * Intercept the execution of a handler in the render phase.
...@@ -208,4 +212,101 @@ public interface HandlerInterceptor { ...@@ -208,4 +212,101 @@ public interface HandlerInterceptor {
RenderRequest request, RenderResponse response, Object handler, Exception ex) RenderRequest request, RenderResponse response, Object handler, Exception ex)
throws Exception; throws Exception;
/**
* Intercept the execution of a handler in the render phase.
* <p>Called after a HandlerMapping determines an appropriate handler object
* to handle a {@link RenderRequest}, but before said HandlerAdapter actually
* invokes the handler.
* <p>{@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 <code>true</code> if the execution chain should proceed with the
* next interceptor or the handler itself. Else, <code>DispatcherPortlet</code>
* 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.
* <p>Called after a {@link HandlerAdapter} actually invoked the handler, but
* before the <code>DispatcherPortlet</code> renders the view. Can thus expose
* additional model objects to the view via the given {@link ModelAndView}.
* <p><code>DispatcherPortlet</code> 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 <code>ModelAndView</code> that the handler returned
* (can also be <code>null</code>)
* @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.
* <p>Note: Will only be called if this interceptor's
* {@link #preHandleRender(javax.portlet.RenderRequest, javax.portlet.RenderResponse, Object)}
* method has successfully completed and returned <code>true</code>!
* @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.
* <p>Called after a HandlerMapping determines an appropriate handler object
* to handle an {@link ActionRequest}, but before said HandlerAdapter actually
* invokes the handler.
* <p>{@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 <code>true</code> if the execution chain should proceed with the
* next interceptor or the handler itself. Else, <code>DispatcherPortlet</code>
* 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.
* <p>Note: Will only be called if this interceptor's
* {@link #preHandleAction(javax.portlet.ActionRequest, javax.portlet.ActionResponse, Object)}
* method has successfully completed and returned <code>true</code>!
* @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 <code>null</code>)
* @throws Exception in case of errors
*/
void afterEventCompletion(
EventRequest request, EventResponse response, Object handler, Exception ex)
throws Exception;
} }
/*
* 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.
* <p>If not specified, the method will be used as default handler:
* i.e. for action requests where no specific action mapping was found.
* <p>Note that all such annotated action methods only apply within the
* <code>@RequestMapping</code> 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.
* <p>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 <i>not</i> supposed to be present in the request.
* @see org.springframework.web.bind.annotation.RequestMapping#params()
*/
String[] params() default {};
}
/*
* 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.
* <p>Typically the local name of the event, but fully qualified names
* with a "{...}" namespace part will be mapped correctly as well.
* <p>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.
* <p>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 <i>not</i> supposed to be present in the request.
* @see org.springframework.web.bind.annotation.RequestMapping#params()
*/
String[] params() default {};
}
/*
* 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.
* <p>If not specified, the render method will be invoked for any
* window state within its general mapping.
* <p>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.
* <p>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 <i>not</i> supposed to be present in the request.
* @see org.springframework.web.bind.annotation.RequestMapping#params()
*/
String[] params() default {};
}
/*
* 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.
* <p>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.
* <p>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 <i>not</i> supposed to be present in the request.
* @see org.springframework.web.bind.annotation.RequestMapping#params()
*/
String[] params() default {};
}
<html>
<body>
Annotations for binding portlet requests to handler methods.
</body>
</html>
...@@ -22,6 +22,7 @@ import java.util.LinkedHashMap; ...@@ -22,6 +22,7 @@ import java.util.LinkedHashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest; import javax.portlet.PortletRequest;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
...@@ -80,6 +81,7 @@ public abstract class AbstractMapBasedHandlerMapping<K> extends AbstractHandlerM ...@@ -80,6 +81,7 @@ public abstract class AbstractMapBasedHandlerMapping<K> extends AbstractHandlerM
Collections.sort(predicates); Collections.sort(predicates);
for (PortletRequestMappingPredicate predicate : predicates) { for (PortletRequestMappingPredicate predicate : predicates) {
if (predicate.match(request)) { if (predicate.match(request)) {
predicate.validate(request);
return predicateMap.get(predicate); return predicateMap.get(predicate);
} }
} }
...@@ -187,6 +189,13 @@ public abstract class AbstractMapBasedHandlerMapping<K> extends AbstractHandlerM ...@@ -187,6 +189,13 @@ public abstract class AbstractMapBasedHandlerMapping<K> extends AbstractHandlerM
* @param request current portlet request * @param request current portlet request
*/ */
boolean match(PortletRequest 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;
} }
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
...@@ -16,21 +16,22 @@ ...@@ -16,21 +16,22 @@
package org.springframework.web.portlet.handler; package org.springframework.web.portlet.handler;
import java.io.IOException;
import javax.portlet.ActionRequest; import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse; import javax.portlet.ActionResponse;
import javax.portlet.RenderRequest; import javax.portlet.EventRequest;
import javax.portlet.RenderResponse; import javax.portlet.EventResponse;
import javax.portlet.PortletRequest; import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse; 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.HandlerInterceptor;
import org.springframework.web.portlet.ModelAndView; 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. * for simplified implementation of pre-only/post-only interceptors.
* *
* @author Juergen Hoeller * @author Juergen Hoeller
...@@ -40,29 +41,31 @@ import org.springframework.web.portlet.ModelAndView; ...@@ -40,29 +41,31 @@ import org.springframework.web.portlet.ModelAndView;
public abstract class HandlerInterceptorAdapter implements HandlerInterceptor { public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {
/** /**
* This implementation delegates to <code>preHandle</code>. * This implementation delegates to {@link #preHandle}.
* @see #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); return preHandle(request, response, handler);
} }
/** /**
* This implementation delegates to <code>afterCompletion</code>. * This implementation delegates to {@link #afterCompletion}.
* @see #afterCompletion
*/ */
public void afterActionCompletion( 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); afterCompletion(request, response, handler, ex);
} }
/** /**
* This implementation delegates to <code>preHandle</code>. * This implementation delegates to {@link #preHandle}.
* @see #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); return preHandle(request, response, handler);
} }
...@@ -70,26 +73,72 @@ public abstract class HandlerInterceptorAdapter implements HandlerInterceptor { ...@@ -70,26 +73,72 @@ public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {
* This implementation is empty. * This implementation is empty.
*/ */
public void postHandleRender( 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 <code>afterCompletion</code>. * This implementation delegates to {@link #afterCompletion}.
* @see #afterCompletion
*/ */
public void afterRenderCompletion( 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); afterCompletion(request, response, handler, ex);
} }
/** /**
* Default callback that both <code>preHandleRender</code> * Default callback that all "pre*" methods delegate to.
* and <code>preHandleAction</code> delegate to.
* <p>This implementation always returns <code>true</code>. * <p>This implementation always returns <code>true</code>.
* @see #preHandleRender
* @see #preHandleAction
*/ */
protected boolean preHandle(PortletRequest request, PortletResponse response, Object handler) protected boolean preHandle(PortletRequest request, PortletResponse response, Object handler)
throws Exception { throws Exception {
...@@ -98,14 +147,12 @@ public abstract class HandlerInterceptorAdapter implements HandlerInterceptor { ...@@ -98,14 +147,12 @@ public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {
} }
/** /**
* Default callback that both <code>preHandleRender</code> * Default callback that all "after*" methods delegate to.
* and <code>preHandleAction</code> delegate to.
* <p>This implementation is empty. * <p>This implementation is empty.
* @see #afterRenderCompletion
* @see #afterActionCompletion
*/ */
protected void afterCompletion( protected void afterCompletion(
PortletRequest request, PortletResponse response, Object handler, Exception ex) throws Exception { PortletRequest request, PortletResponse response, Object handler, Exception ex)
throws Exception {
} }
......
...@@ -16,11 +16,10 @@ ...@@ -16,11 +16,10 @@
package org.springframework.web.portlet.handler; package org.springframework.web.portlet.handler;
import javax.portlet.MimeResponse;
import javax.portlet.PortletException; import javax.portlet.PortletException;
import javax.portlet.PortletRequest; import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse; import javax.portlet.PortletResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import org.springframework.web.portlet.context.PortletApplicationObjectSupport; import org.springframework.web.portlet.context.PortletApplicationObjectSupport;
...@@ -102,7 +101,7 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu ...@@ -102,7 +101,7 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu
* @param response current portlet response * @param response current portlet response
* @throws PortletException if the request cannot be handled because a check failed * @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 { throws PortletException {
checkAndPrepare(request, response, this.cacheSeconds); checkAndPrepare(request, response, this.cacheSeconds);
...@@ -118,8 +117,7 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu ...@@ -118,8 +117,7 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu
* response should be cacheable for, 0 to prevent caching * response should be cacheable for, 0 to prevent caching
* @throws PortletException if the request cannot be handled because a check failed * @throws PortletException if the request cannot be handled because a check failed
*/ */
protected final void checkAndPrepare( protected final void checkAndPrepare(PortletRequest request, MimeResponse response, int cacheSeconds)
RenderRequest request, RenderResponse response, int cacheSeconds)
throws PortletException { throws PortletException {
check(request, response); check(request, response);
...@@ -129,7 +127,7 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu ...@@ -129,7 +127,7 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu
/** /**
* Prevent the render response from being cached. * Prevent the render response from being cached.
*/ */
protected final void preventCaching(RenderResponse response) { protected final void preventCaching(MimeResponse response) {
cacheForSeconds(response, 0); cacheForSeconds(response, 0);
} }
...@@ -139,8 +137,8 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu ...@@ -139,8 +137,8 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu
* @param seconds number of seconds into the future that the response * @param seconds number of seconds into the future that the response
* should be cacheable for * should be cacheable for
*/ */
protected final void cacheForSeconds(RenderResponse response, int seconds) { protected final void cacheForSeconds(MimeResponse response, int seconds) {
response.setProperty(RenderResponse.EXPIRATION_CACHE, Integer.toString(seconds)); response.setProperty(MimeResponse.EXPIRATION_CACHE, Integer.toString(seconds));
} }
/** /**
...@@ -149,7 +147,7 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu ...@@ -149,7 +147,7 @@ public abstract class PortletContentGenerator extends PortletApplicationObjectSu
* @param seconds positive number of seconds into the future that the * @param seconds positive number of seconds into the future that the
* response should be cacheable for, 0 to prevent caching * 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) { if (seconds > 0) {
cacheForSeconds(response, seconds); cacheForSeconds(response, seconds);
} }
......
/*
* 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
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -19,9 +19,12 @@ package org.springframework.web.portlet.handler; ...@@ -19,9 +19,12 @@ package org.springframework.web.portlet.handler;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import javax.portlet.MimeResponse;
import javax.portlet.PortletRequest;
import javax.portlet.RenderRequest; import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse; import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.portlet.WindowState; import javax.portlet.WindowState;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
...@@ -190,6 +193,18 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver, ...@@ -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. * Check whether this resolver is supposed to apply to the given handler.
* <p>The default implementation checks against the specified mapped handlers * <p>The default implementation checks against the specified mapped handlers
...@@ -203,19 +218,19 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver, ...@@ -203,19 +218,19 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
* @see #setMappedHandlers * @see #setMappedHandlers
* @see #setMappedHandlerClasses * @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 the portlet is minimized and we don't want to render then return null.
if (WindowState.MINIMIZED.equals(request.getWindowState()) && !this.renderWhenMinimized) { if (WindowState.MINIMIZED.equals(request.getWindowState()) && !this.renderWhenMinimized) {
return false; return false;
} }
// Check mapped handlers...
if (handler != null) { if (handler != null) {
if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) { if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) {
return true; return true;
} }
if (this.mappedHandlerClasses != null) { if (this.mappedHandlerClasses != null) {
for (int i = 0; i < this.mappedHandlerClasses.length; i++) { for (Class mappedClass : this.mappedHandlerClasses) {
if (this.mappedHandlerClasses[i].isInstance(handler)) { if (mappedClass.isInstance(handler)) {
return true; return true;
} }
} }
...@@ -236,7 +251,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver, ...@@ -236,7 +251,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
* @return a corresponding ModelAndView to forward to, or null for default processing * @return a corresponding ModelAndView to forward to, or null for default processing
*/ */
protected ModelAndView doResolveException( 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. // Log exception, both at debug log level and at warn level, if desired.
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
...@@ -266,7 +281,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver, ...@@ -266,7 +281,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
* @see #buildLogMessage * @see #buildLogMessage
* @see org.apache.commons.logging.Log#warn(Object, Throwable) * @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()) { if (this.warnLogger != null && this.warnLogger.isWarnEnabled()) {
this.warnLogger.warn(buildLogMessage(ex, request), ex); this.warnLogger.warn(buildLogMessage(ex, request), ex);
} }
...@@ -279,7 +294,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver, ...@@ -279,7 +294,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
* @param request current portlet request (useful for obtaining metadata) * @param request current portlet request (useful for obtaining metadata)
* @return the log message to use * @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"; return "Handler execution resulted in exception";
} }
...@@ -292,7 +307,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver, ...@@ -292,7 +307,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
* @param request current portlet request (useful for obtaining metadata) * @param request current portlet request (useful for obtaining metadata)
* @return the resolved view name, or <code>null</code> if none found * @return the resolved view name, or <code>null</code> if none found
*/ */
protected String determineViewName(Exception ex, RenderRequest request) { protected String determineViewName(Exception ex, PortletRequest request) {
String viewName = null; String viewName = null;
// Check for specific exception mappings. // Check for specific exception mappings.
if (this.exceptionMappings != null) { if (this.exceptionMappings != null) {
...@@ -348,7 +363,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver, ...@@ -348,7 +363,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
} }
private int getDepth(String exceptionMapping, Class exceptionClass, int depth) { private int getDepth(String exceptionMapping, Class exceptionClass, int depth) {
if (exceptionClass.getName().indexOf(exceptionMapping) != -1) { if (exceptionClass.getName().contains(exceptionMapping)) {
// Found it! // Found it!
return depth; return depth;
} }
...@@ -369,7 +384,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver, ...@@ -369,7 +384,7 @@ public class SimpleMappingExceptionResolver implements HandlerExceptionResolver,
* @return the ModelAndView instance * @return the ModelAndView instance
* @see #getModelAndView(String, Exception) * @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); return getModelAndView(viewName, ex);
} }
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -18,12 +18,21 @@ package org.springframework.web.portlet.handler; ...@@ -18,12 +18,21 @@ package org.springframework.web.portlet.handler;
import javax.portlet.ActionRequest; import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse; import javax.portlet.ActionResponse;
import javax.portlet.EventPortlet;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.Portlet; import javax.portlet.Portlet;
import javax.portlet.PortletContext;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest; import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse; 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.HandlerAdapter;
import org.springframework.web.portlet.ModelAndView; import org.springframework.web.portlet.ModelAndView;
import org.springframework.web.portlet.context.PortletContextAware;
/** /**
* Adapter to use the Portlet interface with the generic DispatcherPortlet. * Adapter to use the Portlet interface with the generic DispatcherPortlet.
...@@ -49,8 +58,16 @@ import org.springframework.web.portlet.ModelAndView; ...@@ -49,8 +58,16 @@ import org.springframework.web.portlet.ModelAndView;
* @see SimplePortletPostProcessor * @see SimplePortletPostProcessor
* @see org.springframework.web.portlet.mvc.PortletWrappingController * @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) { public boolean supports(Object handler) {
return (handler instanceof Portlet); return (handler instanceof Portlet);
} }
...@@ -68,4 +85,32 @@ public class SimplePortletHandlerAdapter implements HandlerAdapter { ...@@ -68,4 +85,32 @@ public class SimplePortletHandlerAdapter implements HandlerAdapter {
return null; 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);
}
}
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -18,13 +18,16 @@ package org.springframework.web.portlet.handler; ...@@ -18,13 +18,16 @@ package org.springframework.web.portlet.handler;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashSet;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import javax.portlet.Portlet; import javax.portlet.Portlet;
import javax.portlet.PortletConfig; import javax.portlet.PortletConfig;
import javax.portlet.PortletContext; import javax.portlet.PortletContext;
import javax.portlet.PortletException; import javax.portlet.PortletException;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.BeanInitializationException;
...@@ -144,23 +147,47 @@ public class SimplePortletPostProcessor ...@@ -144,23 +147,47 @@ public class SimplePortletPostProcessor
} }
public String getPortletName() { public String getPortletName() {
return portletName; return this.portletName;
} }
public PortletContext getPortletContext() { public PortletContext getPortletContext() {
return portletContext; return this.portletContext;
} }
public String getInitParameter(String paramName) { public String getInitParameter(String paramName) {
return null; return null;
} }
public Enumeration getInitParameterNames() { public Enumeration<String> getInitParameterNames() {
return Collections.enumeration(Collections.EMPTY_SET); return Collections.enumeration(new HashSet<String>());
} }
public ResourceBundle getResourceBundle(Locale locale) { public ResourceBundle getResourceBundle(Locale locale) {
return portletConfig == null ? null : portletConfig.getResourceBundle(locale); return (this.portletConfig != null ? this.portletConfig.getResourceBundle(locale) : null);
}
public Enumeration<String> getPublicRenderParameterNames() {
return Collections.enumeration(new HashSet<String>());
}
public String getDefaultNamespace() {
return XMLConstants.NULL_NS_URI;
}
public Enumeration<QName> getPublishingEventQNames() {
return Collections.enumeration(new HashSet<QName>());
}
public Enumeration<QName> getProcessingEventQNames() {
return Collections.enumeration(new HashSet<QName>());
}
public Enumeration<Locale> getSupportedLocales() {
return Collections.enumeration(new HashSet<Locale>());
}
public Map<String, String[]> getContainerRuntimeOptions() {
return (this.portletConfig != null ? this.portletConfig.getContainerRuntimeOptions() : null);
} }
} }
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -51,8 +51,8 @@ public class UserRoleAuthorizationInterceptor extends HandlerInterceptorAdapter ...@@ -51,8 +51,8 @@ public class UserRoleAuthorizationInterceptor extends HandlerInterceptorAdapter
throws PortletException, IOException { throws PortletException, IOException {
if (this.authorizedRoles != null) { if (this.authorizedRoles != null) {
for (int i = 0; i < this.authorizedRoles.length; i++) { for (String role : this.authorizedRoles) {
if (request.isUserInRole(this.authorizedRoles[i])) { if (request.isUserInRole(role)) {
return true; return true;
} }
} }
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -18,8 +18,12 @@ package org.springframework.web.portlet.handler; ...@@ -18,8 +18,12 @@ package org.springframework.web.portlet.handler;
import javax.portlet.ActionRequest; import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse; import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.RenderRequest; import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse; import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.web.context.request.WebRequestInterceptor; import org.springframework.web.context.request.WebRequestInterceptor;
...@@ -105,4 +109,35 @@ public class WebRequestHandlerInterceptorAdapter implements HandlerInterceptor { ...@@ -105,4 +109,35 @@ public class WebRequestHandlerInterceptorAdapter implements HandlerInterceptor {
this.requestInterceptor.afterCompletion(new PortletWebRequest(request), ex); 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);
}
} }
...@@ -24,9 +24,9 @@ import java.util.Iterator; ...@@ -24,9 +24,9 @@ import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.portlet.ActionRequest; import javax.portlet.ActionRequest;
import javax.portlet.filter.ActionRequestWrapper;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.portlet.util.ActionRequestWrapper;
/** /**
* Default implementation of the {@link MultipartActionRequest} interface. * Default implementation of the {@link MultipartActionRequest} interface.
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -122,6 +122,8 @@ import org.springframework.web.portlet.util.PortletUtils; ...@@ -122,6 +122,8 @@ import org.springframework.web.portlet.util.PortletUtils;
* @author John A. Lewis * @author John A. Lewis
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.0 * @since 2.0
* @see ResourceAwareController
* @see EventAwareController
*/ */
public abstract class AbstractController extends PortletContentGenerator implements Controller { public abstract class AbstractController extends PortletContentGenerator implements Controller {
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -45,15 +45,7 @@ import org.springframework.web.portlet.ModelAndView; ...@@ -45,15 +45,7 @@ import org.springframework.web.portlet.ModelAndView;
* request and - if applicable - returning an appropriate ModelAndView. * request and - if applicable - returning an appropriate ModelAndView.
* So actually, these method are the main entrypoint for the * So actually, these method are the main entrypoint for the
* {@link org.springframework.web.portlet.DispatcherPortlet DispatcherPortlet} * {@link org.springframework.web.portlet.DispatcherPortlet DispatcherPortlet}
* which delegates requests to controllers. These method - and also this interface - * which delegates requests to controllers.</p>
* should preferrably not be implemented by custom controllers <i>directly</i>, 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}.</p>
* *
* <p>So basically any <i>direct</i> implementation of the Controller interface * <p>So basically any <i>direct</i> implementation of the Controller interface
* just handles RenderRequests/ActionRequests and should return a ModelAndView, to be * just handles RenderRequests/ActionRequests and should return a ModelAndView, to be
...@@ -64,19 +56,16 @@ import org.springframework.web.portlet.ModelAndView; ...@@ -64,19 +56,16 @@ import org.springframework.web.portlet.ModelAndView;
* @author William G. Thompson, Jr. * @author William G. Thompson, Jr.
* @author John A. Lewis * @author John A. Lewis
* @since 2.0 * @since 2.0
* @see ResourceAwareController
* @see EventAwareController
* @see SimpleControllerHandlerAdapter * @see SimpleControllerHandlerAdapter
* @see AbstractController * @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 * @see org.springframework.web.portlet.context.PortletContextAware
*/ */
public interface Controller { 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 request current portlet action request
* @param response current portlet action response * @param response current portlet action response
* @throws Exception in case of errors * @throws Exception in case of errors
......
/*
* 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;
}
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,11 +16,13 @@ ...@@ -16,11 +16,13 @@
package org.springframework.web.portlet.mvc; package org.springframework.web.portlet.mvc;
import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Properties; import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import javax.portlet.ActionRequest; import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse; import javax.portlet.ActionResponse;
import javax.portlet.Portlet; import javax.portlet.Portlet;
...@@ -28,6 +30,8 @@ import javax.portlet.PortletConfig; ...@@ -28,6 +30,8 @@ import javax.portlet.PortletConfig;
import javax.portlet.PortletContext; import javax.portlet.PortletContext;
import javax.portlet.RenderRequest; import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse; import javax.portlet.RenderResponse;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
...@@ -79,7 +83,7 @@ public class PortletWrappingController extends AbstractController ...@@ -79,7 +83,7 @@ public class PortletWrappingController extends AbstractController
private String portletName; private String portletName;
private Properties initParameters = new Properties(); private Map<String, String> initParameters = new LinkedHashMap<String, String>();
private String beanName; private String beanName;
...@@ -128,7 +132,7 @@ public class PortletWrappingController extends AbstractController ...@@ -128,7 +132,7 @@ public class PortletWrappingController extends AbstractController
* Specify init parameters for the portlet to wrap, * Specify init parameters for the portlet to wrap,
* as name-value pairs. * as name-value pairs.
*/ */
public void setInitParameters(Properties initParameters) { public void setInitParameters(Map<String, String> initParameters) {
this.initParameters = initParameters; this.initParameters = initParameters;
} }
...@@ -195,17 +199,40 @@ public class PortletWrappingController extends AbstractController ...@@ -195,17 +199,40 @@ public class PortletWrappingController extends AbstractController
} }
public String getInitParameter(String paramName) { public String getInitParameter(String paramName) {
return initParameters.getProperty(paramName); return initParameters.get(paramName);
} }
public Enumeration getInitParameterNames() { public Enumeration<String> getInitParameterNames() {
return initParameters.keys(); return Collections.enumeration(initParameters.keySet());
} }
public ResourceBundle getResourceBundle(Locale locale) { public ResourceBundle getResourceBundle(Locale locale) {
return (portletConfig != null ? portletConfig.getResourceBundle(locale) : null); return (portletConfig != null ? portletConfig.getResourceBundle(locale) : null);
} }
public Enumeration<String> getPublicRenderParameterNames() {
return Collections.enumeration(new HashSet<String>());
}
public String getDefaultNamespace() {
return XMLConstants.NULL_NS_URI;
}
public Enumeration<QName> getPublishingEventQNames() {
return Collections.enumeration(new HashSet<QName>());
}
public Enumeration<QName> getProcessingEventQNames() {
return Collections.enumeration(new HashSet<QName>());
}
public Enumeration<Locale> getSupportedLocales() {
return Collections.enumeration(new HashSet<Locale>());
}
public Map<String, String[]> getContainerRuntimeOptions() {
return (portletConfig != null ? portletConfig.getContainerRuntimeOptions() : null);
}
} }
} }
/*
* 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 <code>null</code> 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;
}
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -18,24 +18,42 @@ package org.springframework.web.portlet.mvc; ...@@ -18,24 +18,42 @@ package org.springframework.web.portlet.mvc;
import javax.portlet.ActionRequest; import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse; 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.RenderRequest;
import javax.portlet.RenderResponse; import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import org.springframework.web.portlet.HandlerAdapter; import org.springframework.web.portlet.HandlerAdapter;
import org.springframework.web.portlet.ModelAndView; import org.springframework.web.portlet.ModelAndView;
import org.springframework.web.portlet.context.PortletContextAware;
/** /**
* Adapter to use the Controller workflow interface with the generic DispatcherPortlet. * Adapter to use the Controller workflow interface with the generic DispatcherPortlet.
* *
* <p>This is an SPI class, not used directly by application code. * <p>This is an SPI class, not used directly by application code.
* *
* @author Juergen Hoeller
* @author John A. Lewis * @author John A. Lewis
* @since 2.0 * @since 2.0
* @see org.springframework.web.portlet.DispatcherPortlet * @see org.springframework.web.portlet.DispatcherPortlet
* @see Controller * @see Controller
*/ * @see ResourceAwareController
public class SimpleControllerHandlerAdapter implements HandlerAdapter { * @see EventAwareController
*/
public class SimpleControllerHandlerAdapter implements HandlerAdapter, PortletContextAware {
private PortletContext portletContext;
public void setPortletContext(PortletContext portletContext) {
this.portletContext = portletContext;
}
public boolean supports(Object handler) { public boolean supports(Object handler) {
return (handler instanceof Controller); return (handler instanceof Controller);
} }
...@@ -52,4 +70,32 @@ public class SimpleControllerHandlerAdapter implements HandlerAdapter { ...@@ -52,4 +70,32 @@ public class SimpleControllerHandlerAdapter implements HandlerAdapter {
return ((Controller) handler).handleRenderRequest(request, response); 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);
}
}
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -23,13 +23,20 @@ import java.io.Writer; ...@@ -23,13 +23,20 @@ import java.io.Writer;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.security.Principal; import java.security.Principal;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import javax.portlet.ActionRequest; import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse; 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.PortalContext;
import javax.portlet.PortletException; import javax.portlet.PortletException;
import javax.portlet.PortletMode; import javax.portlet.PortletMode;
...@@ -39,6 +46,8 @@ import javax.portlet.PortletResponse; ...@@ -39,6 +46,8 @@ import javax.portlet.PortletResponse;
import javax.portlet.PortletSession; import javax.portlet.PortletSession;
import javax.portlet.RenderRequest; import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse; import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.portlet.UnavailableException; import javax.portlet.UnavailableException;
import javax.portlet.WindowState; import javax.portlet.WindowState;
...@@ -54,11 +63,14 @@ import org.springframework.ui.ExtendedModelMap; ...@@ -54,11 +63,14 @@ import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.support.BindingAwareModelMap; import org.springframework.validation.support.BindingAwareModelMap;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping; 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.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.annotation.support.HandlerMethodInvoker; import org.springframework.web.bind.annotation.support.HandlerMethodInvoker;
...@@ -72,6 +84,10 @@ import org.springframework.web.portlet.HandlerAdapter; ...@@ -72,6 +84,10 @@ import org.springframework.web.portlet.HandlerAdapter;
import org.springframework.web.portlet.ModelAndView; import org.springframework.web.portlet.ModelAndView;
import org.springframework.web.portlet.bind.MissingPortletRequestParameterException; import org.springframework.web.portlet.bind.MissingPortletRequestParameterException;
import org.springframework.web.portlet.bind.PortletRequestDataBinder; 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.context.PortletWebRequest;
import org.springframework.web.portlet.handler.PortletContentGenerator; import org.springframework.web.portlet.handler.PortletContentGenerator;
import org.springframework.web.portlet.handler.PortletSessionRequiredException; import org.springframework.web.portlet.handler.PortletSessionRequiredException;
...@@ -218,14 +234,25 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl ...@@ -218,14 +234,25 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
return doHandle(request, response, handler); 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 { protected ModelAndView doHandle(PortletRequest request, PortletResponse response, Object handler) throws Exception {
ExtendedModelMap implicitModel = null; ExtendedModelMap implicitModel = null;
if (request instanceof RenderRequest && response instanceof RenderResponse) { if (response instanceof MimeResponse) {
RenderRequest renderRequest = (RenderRequest) request; MimeResponse mimeResponse = (MimeResponse) response;
RenderResponse renderResponse = (RenderResponse) response;
// Detect implicit model from associated action phase. // 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); PortletSession session = request.getPortletSession(false);
if (session != null) { if (session != null) {
implicitModel = (ExtendedModelMap) session.getAttribute(IMPLICIT_MODEL_ATTRIBUTE); implicitModel = (ExtendedModelMap) session.getAttribute(IMPLICIT_MODEL_ATTRIBUTE);
...@@ -233,11 +260,11 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl ...@@ -233,11 +260,11 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
} }
if (handler.getClass().getAnnotation(SessionAttributes.class) != null) { if (handler.getClass().getAnnotation(SessionAttributes.class) != null) {
// Always prevent caching in case of session attribute management. // Always prevent caching in case of session attribute management.
checkAndPrepare(renderRequest, renderResponse, this.cacheSecondsForSessionAttributeHandlers); checkAndPrepare(request, mimeResponse, this.cacheSecondsForSessionAttributeHandlers);
} }
else { else {
// Uses configured default cacheSeconds setting. // Uses configured default cacheSeconds setting.
checkAndPrepare(renderRequest, renderResponse); checkAndPrepare(request, mimeResponse);
} }
} }
...@@ -265,7 +292,7 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl ...@@ -265,7 +292,7 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
PortletWebRequest webRequest = new PortletWebRequest(request, response); PortletWebRequest webRequest = new PortletWebRequest(request, response);
PortletHandlerMethodResolver methodResolver = getMethodResolver(handler); PortletHandlerMethodResolver methodResolver = getMethodResolver(handler);
Method handlerMethod = methodResolver.resolveHandlerMethod(request, response); Method handlerMethod = methodResolver.resolveHandlerMethod(request);
PortletHandlerMethodInvoker methodInvoker = new PortletHandlerMethodInvoker(methodResolver); PortletHandlerMethodInvoker methodInvoker = new PortletHandlerMethodInvoker(methodResolver);
Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel); Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
...@@ -324,42 +351,51 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl ...@@ -324,42 +351,51 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
private static class PortletHandlerMethodResolver extends HandlerMethodResolver { private static class PortletHandlerMethodResolver extends HandlerMethodResolver {
private final Map<Method, RequestMappingInfo> mappings = new HashMap<Method, RequestMappingInfo>();
public PortletHandlerMethodResolver(Class<?> handlerType) { public PortletHandlerMethodResolver(Class<?> handlerType) {
super(handlerType); init(handlerType);
} }
public Method resolveHandlerMethod(PortletRequest request, PortletResponse response) throws PortletException { @Override
String lookupMode = request.getPortletMode().toString(); 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<RequestMappingInfo, Method> targetHandlerMethods = new LinkedHashMap<RequestMappingInfo, Method>(); Map<RequestMappingInfo, Method> targetHandlerMethods = new LinkedHashMap<RequestMappingInfo, Method>();
for (Method handlerMethod : getHandlerMethods()) { for (Method handlerMethod : getHandlerMethods()) {
RequestMapping mapping = AnnotationUtils.findAnnotation(handlerMethod, RequestMapping.class); RequestMappingInfo mappingInfo = this.mappings.get(handlerMethod);
RequestMappingInfo mappingInfo = new RequestMappingInfo(); if (mappingInfo.match(request)) {
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) {
Method oldMappedMethod = targetHandlerMethods.put(mappingInfo, handlerMethod); Method oldMappedMethod = targetHandlerMethods.put(mappingInfo, handlerMethod);
if (oldMappedMethod != null && oldMappedMethod != handlerMethod) { if (oldMappedMethod != null && oldMappedMethod != handlerMethod) {
throw new IllegalStateException("Ambiguous handler methods mapped for portlet mode '" + 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 " + "}. 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!"); "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 ...@@ -376,8 +412,7 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
bestMappingMatch = mapping; bestMappingMatch = mapping;
} }
else { else {
if ((bestMappingMatch.modes.length == 0 && mapping.modes.length > 0) || if (mapping.isBetterMatchThan(bestMappingMatch)) {
bestMappingMatch.params.length < mapping.params.length) {
bestMappingMatch = mapping; bestMappingMatch = mapping;
} }
} }
...@@ -386,50 +421,123 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl ...@@ -386,50 +421,123 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
} }
} }
else { else {
throw new UnavailableException("No matching handler method found for portlet request: mode '" + throw new UnavailableException(
request.getPortletMode() + "', type '" + (response instanceof ActionResponse ? "action" : "render") + "No matching handler method found for portlet request: mode '" + request.getPortletMode() +
"', phase '" + request.getAttribute(PortletRequest.LIFECYCLE_PHASE) +
"', parameters " + StylerUtils.style(request.getParameterMap())); "', parameters " + StylerUtils.style(request.getParameterMap()));
} }
} }
private boolean checkParameters(PortletRequest request, PortletResponse response, RequestMappingInfo mapping) { private String determineDefaultPhase(Method handlerMethod) {
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) {
if (!void.class.equals(handlerMethod.getReturnType())) { if (!void.class.equals(handlerMethod.getReturnType())) {
return false; return PortletRequest.RENDER_PHASE;
} }
for (Class<?> argType : handlerMethod.getParameterTypes()) { for (Class<?> argType : handlerMethod.getParameterTypes()) {
if (ActionRequest.class.isAssignableFrom(argType) || ActionResponse.class.isAssignableFrom(argType) || if (ActionRequest.class.isAssignableFrom(argType) || ActionResponse.class.isAssignableFrom(argType) ||
InputStream.class.isAssignableFrom(argType) || Reader.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())) { private static class RequestMappingInfo {
return true;
public Set<PortletMode> modes = new HashSet<PortletMode>();
public String phase;
public String value;
public Set<String> methods = new HashSet<String>();
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()) { for (RequestMethod method : methods) {
if (RenderRequest.class.isAssignableFrom(argType) || RenderResponse.class.isAssignableFrom(argType) || this.methods.add(method.name());
OutputStream.class.isAssignableFrom(argType) || Writer.class.isAssignableFrom(argType)) { }
return true; 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 ...@@ -505,28 +613,34 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
return request.getLocale(); return request.getLocale();
} }
else if (InputStream.class.isAssignableFrom(parameterType)) { else if (InputStream.class.isAssignableFrom(parameterType)) {
if (!(request instanceof ActionRequest)) { if (!(request instanceof ClientDataRequest)) {
throw new IllegalStateException("InputStream can only get obtained for ActionRequest"); 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)) { else if (Reader.class.isAssignableFrom(parameterType)) {
if (!(request instanceof ActionRequest)) { if (!(request instanceof ClientDataRequest)) {
throw new IllegalStateException("Reader can only get obtained for ActionRequest"); 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)) { else if (OutputStream.class.isAssignableFrom(parameterType)) {
if (!(response instanceof RenderResponse)) { if (!(response instanceof MimeResponse)) {
throw new IllegalStateException("OutputStream can only get obtained for RenderResponse"); 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)) { else if (Writer.class.isAssignableFrom(parameterType)) {
if (!(response instanceof RenderResponse)) { if (!(response instanceof MimeResponse)) {
throw new IllegalStateException("Writer can only get obtained for RenderResponse"); 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); return super.resolveStandardArgument(parameterType, webRequest);
} }
...@@ -581,28 +695,4 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl ...@@ -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));
}
}
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,9 +16,12 @@ ...@@ -16,9 +16,12 @@
package org.springframework.web.portlet.mvc.annotation; package org.springframework.web.portlet.mvc.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import javax.portlet.ClientDataRequest;
import javax.portlet.PortletException;
import javax.portlet.PortletMode; import javax.portlet.PortletMode;
import javax.portlet.PortletRequest; import javax.portlet.PortletRequest;
...@@ -28,8 +31,11 @@ import org.springframework.core.annotation.AnnotationUtils; ...@@ -28,8 +31,11 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils; 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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.portlet.handler.AbstractMapBasedHandlerMapping; import org.springframework.web.portlet.handler.AbstractMapBasedHandlerMapping;
import org.springframework.web.portlet.handler.PortletRequestMethodNotSupportedException;
/** /**
* Implementation of the {@link org.springframework.web.portlet.HandlerMapping} * Implementation of the {@link org.springframework.web.portlet.HandlerMapping}
...@@ -99,12 +105,13 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp ...@@ -99,12 +105,13 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp
if (mapping != null) { if (mapping != null) {
String[] modeKeys = mapping.value(); String[] modeKeys = mapping.value();
String[] params = mapping.params(); String[] params = mapping.params();
RequestMethod[] methods = mapping.method();
boolean registerHandlerType = true; boolean registerHandlerType = true;
if (modeKeys.length == 0 || params.length == 0) { if (modeKeys.length == 0 || params.length == 0) {
registerHandlerType = !detectHandlerMethods(handlerType, beanName, mapping); registerHandlerType = !detectHandlerMethods(handlerType, beanName, mapping);
} }
if (registerHandlerType) { if (registerHandlerType) {
ParameterMappingPredicate predicate = new ParameterMappingPredicate(params); ParameterMappingPredicate predicate = new ParameterMappingPredicate(params, methods);
for (String modeKey : modeKeys) { for (String modeKey : modeKeys) {
registerHandler(new PortletMode(modeKey), beanName, predicate); registerHandler(new PortletMode(modeKey), beanName, predicate);
} }
...@@ -128,9 +135,20 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp ...@@ -128,9 +135,20 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp
final Set<Boolean> handlersRegistered = new HashSet<Boolean>(1); final Set<Boolean> handlersRegistered = new HashSet<Boolean>(1);
ReflectionUtils.doWithMethods(handlerType, new ReflectionUtils.MethodCallback() { ReflectionUtils.doWithMethods(handlerType, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) { public void doWith(Method method) {
RequestMapping mapping = method.getAnnotation(RequestMapping.class); boolean mappingFound = false;
if (mapping != null) { String[] modeKeys = new String[0];
String[] modeKeys = mapping.value(); 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 (modeKeys.length == 0) {
if (typeMapping != null) { if (typeMapping != null) {
modeKeys = typeMapping.value(); modeKeys = typeMapping.value();
...@@ -140,7 +158,6 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp ...@@ -140,7 +158,6 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp
"No portlet mode mappings specified - neither at type nor method level"); "No portlet mode mappings specified - neither at type nor method level");
} }
} }
String[] params = mapping.params();
if (typeMapping != null) { if (typeMapping != null) {
PortletAnnotationMappingUtils.validateModeMapping(modeKeys, typeMapping.value()); PortletAnnotationMappingUtils.validateModeMapping(modeKeys, typeMapping.value());
params = StringUtils.mergeStringArrays(typeMapping.params(), params); params = StringUtils.mergeStringArrays(typeMapping.params(), params);
...@@ -172,14 +189,35 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp ...@@ -172,14 +189,35 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp
private final String[] params; private final String[] params;
private ParameterMappingPredicate(String[] params) { private final Set<String> methods = new HashSet<String>();
public ParameterMappingPredicate(String[] params) {
this.params = params;
}
public ParameterMappingPredicate(String[] params, RequestMethod[] methods) {
this.params = params; this.params = params;
for (RequestMethod method : methods) {
this.methods.add(method.name());
}
} }
public boolean match(PortletRequest request) { public boolean match(PortletRequest request) {
return PortletAnnotationMappingUtils.checkParameters(this.params, 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) { public int compareTo(Object other) {
if (other instanceof PortletRequestMappingPredicate) { if (other instanceof PortletRequestMappingPredicate) {
return new Integer(((ParameterMappingPredicate) other).params.length).compareTo(this.params.length); return new Integer(((ParameterMappingPredicate) other).params.length).compareTo(this.params.length);
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package org.springframework.web.portlet.mvc.annotation; package org.springframework.web.portlet.mvc.annotation;
import java.util.Set;
import javax.portlet.ClientDataRequest;
import javax.portlet.PortletRequest; import javax.portlet.PortletRequest;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
...@@ -30,7 +32,7 @@ import org.springframework.web.portlet.util.PortletUtils; ...@@ -30,7 +32,7 @@ import org.springframework.web.portlet.util.PortletUtils;
abstract class PortletAnnotationMappingUtils { 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 modes the mapped portlet modes to check
* @param typeLevelModes the type-level mode mappings to check against * @param typeLevelModes the type-level mode mappings to check against
*/ */
...@@ -51,11 +53,29 @@ abstract class PortletAnnotationMappingUtils { ...@@ -51,11 +53,29 @@ abstract class PortletAnnotationMappingUtils {
return true; 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<String> 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. * Check whether the given request matches the specified parameter conditions.
* @param params the parameter conditions, following * @param params the parameter conditions, following
* {@link org.springframework.web.bind.annotation.RequestMapping#params()} * {@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) { public static boolean checkParameters(String[] params, PortletRequest request) {
if (!ObjectUtils.isEmpty(params)) { if (!ObjectUtils.isEmpty(params)) {
......
/*
* 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.
*
* <p>(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 <code>request</code> is <code>null</code>
*/
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();
}
}
/*
* 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.
*
* <p>(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 <code>request</code> is <code>null</code>
*/
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();
}
}
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,14 +16,6 @@ ...@@ -16,14 +16,6 @@
package org.springframework.mock.web.portlet; 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.ActionRequest;
import javax.portlet.PortalContext; import javax.portlet.PortalContext;
import javax.portlet.PortletContext; import javax.portlet.PortletContext;
...@@ -36,25 +28,28 @@ import javax.portlet.PortletMode; ...@@ -36,25 +28,28 @@ import javax.portlet.PortletMode;
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.0 * @since 2.0
*/ */
public class MockActionRequest extends MockPortletRequest implements ActionRequest { public class MockActionRequest extends MockClientDataRequest implements ActionRequest {
private String characterEncoding;
private byte[] content;
private String contentType;
/** /**
* Create a new MockActionRequest with a default {@link MockPortalContext} * Create a new MockActionRequest with a default {@link MockPortalContext}
* and a default {@link MockPortletContext}. * and a default {@link MockPortletContext}.
* @see MockPortalContext * @see org.springframework.mock.web.portlet.MockPortalContext
* @see MockPortletContext * @see org.springframework.mock.web.portlet.MockPortletContext
*/ */
public MockActionRequest() { public MockActionRequest() {
super(); 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} * Create a new MockActionRequest with a default {@link MockPortalContext}
* and a default {@link MockPortletContext}. * and a default {@link MockPortletContext}.
...@@ -83,49 +78,9 @@ public class MockActionRequest extends MockPortletRequest implements ActionReque ...@@ -83,49 +78,9 @@ public class MockActionRequest extends MockPortletRequest implements ActionReque
} }
public void setContent(byte[] content) { @Override
this.content = content; protected String getLifecyclePhase() {
} return ACTION_PHASE;
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);
} }
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -17,7 +17,9 @@ ...@@ -17,7 +17,9 @@
package org.springframework.mock.web.portlet; package org.springframework.mock.web.portlet;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
...@@ -27,6 +29,7 @@ import javax.portlet.PortletMode; ...@@ -27,6 +29,7 @@ import javax.portlet.PortletMode;
import javax.portlet.PortletModeException; import javax.portlet.PortletModeException;
import javax.portlet.WindowState; import javax.portlet.WindowState;
import javax.portlet.WindowStateException; import javax.portlet.WindowStateException;
import javax.xml.namespace.QName;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
...@@ -38,16 +41,12 @@ import org.springframework.util.CollectionUtils; ...@@ -38,16 +41,12 @@ import org.springframework.util.CollectionUtils;
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.0 * @since 2.0
*/ */
public class MockActionResponse extends MockPortletResponse implements ActionResponse { public class MockActionResponse extends MockStateAwareResponse implements ActionResponse {
private WindowState windowState; private boolean redirectAllowed = true;
private PortletMode portletMode;
private String redirectedUrl; private String redirectedUrl;
private final Map<String, String[]> renderParameters = new LinkedHashMap<String, String[]>();
/** /**
* Create a new MockActionResponse with a default {@link MockPortalContext}. * Create a new MockActionResponse with a default {@link MockPortalContext}.
...@@ -71,93 +70,60 @@ public class MockActionResponse extends MockPortletResponse implements ActionRes ...@@ -71,93 +70,60 @@ public class MockActionResponse extends MockPortletResponse implements ActionRes
if (this.redirectedUrl != null) { if (this.redirectedUrl != null) {
throw new IllegalStateException("Cannot set WindowState after sendRedirect has been called"); throw new IllegalStateException("Cannot set WindowState after sendRedirect has been called");
} }
if (!CollectionUtils.contains(getPortalContext().getSupportedWindowStates(), windowState)) { super.setWindowState(windowState);
throw new WindowStateException("WindowState not supported", windowState); this.redirectAllowed = false;
}
this.windowState = windowState;
}
public WindowState getWindowState() {
return windowState;
} }
public void setPortletMode(PortletMode portletMode) throws PortletModeException { public void setPortletMode(PortletMode portletMode) throws PortletModeException {
if (this.redirectedUrl != null) { if (this.redirectedUrl != null) {
throw new IllegalStateException("Cannot set PortletMode after sendRedirect has been called"); throw new IllegalStateException("Cannot set PortletMode after sendRedirect has been called");
} }
if (!CollectionUtils.contains(getPortalContext().getSupportedPortletModes(), portletMode)) { super.setPortletMode(portletMode);
throw new PortletModeException("PortletMode not supported", portletMode); this.redirectAllowed = false;
}
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;
} }
public String getRedirectedUrl() { public void setRenderParameters(Map<String, String[]> parameters) {
return redirectedUrl;
}
public void setRenderParameters(Map parameters) {
if (this.redirectedUrl != null) { if (this.redirectedUrl != null) {
throw new IllegalStateException("Cannot set render parameters after sendRedirect has been called"); throw new IllegalStateException("Cannot set render parameters after sendRedirect has been called");
} }
Assert.notNull(parameters, "Parameters Map must not be null"); super.setRenderParameters(parameters);
this.renderParameters.clear(); this.redirectAllowed = false;
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());
}
} }
public void setRenderParameter(String key, String value) { public void setRenderParameter(String key, String value) {
if (this.redirectedUrl != null) { if (this.redirectedUrl != null) {
throw new IllegalStateException("Cannot set render parameters after sendRedirect has been called"); throw new IllegalStateException("Cannot set render parameters after sendRedirect has been called");
} }
Assert.notNull(key, "Parameter key must not be null"); super.setRenderParameter(key, value);
Assert.notNull(value, "Parameter value must not be null"); this.redirectAllowed = false;
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);
} }
public void setRenderParameter(String key, String[] values) { public void setRenderParameter(String key, String[] values) {
if (this.redirectedUrl != null) { if (this.redirectedUrl != null) {
throw new IllegalStateException("Cannot set render parameters after sendRedirect has been called"); throw new IllegalStateException("Cannot set render parameters after sendRedirect has been called");
} }
Assert.notNull(key, "Parameter key must not be null"); super.setRenderParameter(key, values);
Assert.notNull(values, "Parameter values must not be null"); this.redirectAllowed = false;
this.renderParameters.put(key, values);
} }
public String[] getRenderParameterValues(String key) { public void sendRedirect(String location) throws IOException {
Assert.notNull(key, "Parameter key must not be null"); if (!this.redirectAllowed) {
return this.renderParameters.get(key); 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() { public void sendRedirect(String location, String renderUrlParamName) throws IOException {
return this.renderParameters.keySet().iterator(); sendRedirect(location);
if (renderUrlParamName != null) {
setRenderParameter(renderUrlParamName, location);
}
} }
public Map getRenderParameterMap() { public String getRedirectedUrl() {
return Collections.unmodifiableMap(this.renderParameters); return this.redirectedUrl;
} }
} }
/*
* 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<String, String[]> parameters = new LinkedHashMap<String, String[]>();
private boolean secure = false;
private final Map<String, String[]> properties = new LinkedHashMap<String, String[]>();
//---------------------------------------------------------------------
// 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<String, String[]> parameters) {
Assert.notNull(parameters, "Parameters Map must not be null");
this.parameters.clear();
this.parameters.putAll(parameters);
}
public Set<String> 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<String, String[]> 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<String, String[]> 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;
}
}
}
/*
* 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;
}
}
/*
* 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
/*
* 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
/*
* 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
/*
* 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());
}
}
/*
* 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<String> 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;
}
}
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,16 +16,19 @@ ...@@ -16,16 +16,19 @@
package org.springframework.mock.web.portlet; package org.springframework.mock.web.portlet;
import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.LinkedHashMap; import java.util.Set;
import java.util.Collections;
import javax.portlet.PortletConfig; import javax.portlet.PortletConfig;
import javax.portlet.PortletContext; import javax.portlet.PortletContext;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import org.springframework.util.Assert; import org.springframework.util.Assert;
...@@ -46,6 +49,18 @@ public class MockPortletConfig implements PortletConfig { ...@@ -46,6 +49,18 @@ public class MockPortletConfig implements PortletConfig {
private final Map<String, String> initParameters = new LinkedHashMap<String, String>(); private final Map<String, String> initParameters = new LinkedHashMap<String, String>();
private final Set<String> publicRenderParameterNames = new LinkedHashSet<String>();
private String defaultNamespace = XMLConstants.NULL_NS_URI;
private final Set<QName> publishingEventQNames = new LinkedHashSet<QName>();
private final Set<QName> processingEventQNames = new LinkedHashSet<QName>();
private final Set<Locale> supportedLocales = new LinkedHashSet<Locale>();
private final Map<String, String[]> containerRuntimeOptions = new LinkedHashMap<String, String[]>();
/** /**
* Create a new MockPortletConfig with a default {@link MockPortletContext}. * Create a new MockPortletConfig with a default {@link MockPortletContext}.
...@@ -113,4 +128,56 @@ public class MockPortletConfig implements PortletConfig { ...@@ -113,4 +128,56 @@ public class MockPortletConfig implements PortletConfig {
return Collections.enumeration(this.initParameters.keySet()); return Collections.enumeration(this.initParameters.keySet());
} }
public void addPublicRenderParameterName(String name) {
this.publicRenderParameterNames.add(name);
}
public Enumeration<String> 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<QName> getPublishingEventQNames() {
return Collections.enumeration(this.publishingEventQNames);
}
public void addProcessingEventQName(QName name) {
this.processingEventQNames.add(name);
}
public Enumeration<QName> getProcessingEventQNames() {
return Collections.enumeration(this.processingEventQNames);
}
public void addSupportedLocale(Locale locale) {
this.supportedLocales.add(locale);
}
public Enumeration<Locale> 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<String, String[]> getContainerRuntimeOptions() {
return Collections.unmodifiableMap(this.containerRuntimeOptions);
}
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -25,6 +25,7 @@ import java.util.Collections; ...@@ -25,6 +25,7 @@ import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.portlet.PortletContext; import javax.portlet.PortletContext;
...@@ -63,6 +64,8 @@ public class MockPortletContext implements PortletContext { ...@@ -63,6 +64,8 @@ public class MockPortletContext implements PortletContext {
private String portletContextName = "MockPortletContext"; private String portletContextName = "MockPortletContext";
private Set<String> containerRuntimeOptions = new LinkedHashSet<String>();
/** /**
* Create a new MockPortletContext with no base path and a * Create a new MockPortletContext with no base path and a
...@@ -248,7 +251,15 @@ public class MockPortletContext implements PortletContext { ...@@ -248,7 +251,15 @@ public class MockPortletContext implements PortletContext {
} }
public String getPortletContextName() { public String getPortletContextName() {
return portletContextName; return this.portletContextName;
}
public void addContainerRuntimeOption(String key) {
this.containerRuntimeOptions.add(key);
}
public Enumeration<String> getContainerRuntimeOptions() {
return Collections.enumeration(this.containerRuntimeOptions);
} }
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -33,6 +33,7 @@ import javax.portlet.PortletPreferences; ...@@ -33,6 +33,7 @@ import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest; import javax.portlet.PortletRequest;
import javax.portlet.PortletSession; import javax.portlet.PortletSession;
import javax.portlet.WindowState; import javax.portlet.WindowState;
import javax.servlet.http.Cookie;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
...@@ -90,6 +91,12 @@ public class MockPortletRequest implements PortletRequest { ...@@ -90,6 +91,12 @@ public class MockPortletRequest implements PortletRequest {
private int serverPort = 80; private int serverPort = 80;
private String windowID;
private Cookie[] cookies;
private final Set<String> publicParameterNames = new HashSet<String>();
/** /**
* Create a new MockPortletRequest with a default {@link MockPortalContext} * Create a new MockPortletRequest with a default {@link MockPortalContext}
...@@ -120,6 +127,7 @@ public class MockPortletRequest implements PortletRequest { ...@@ -120,6 +127,7 @@ public class MockPortletRequest implements PortletRequest {
this.portletContext = (portletContext != null ? portletContext : new MockPortletContext()); this.portletContext = (portletContext != null ? portletContext : new MockPortletContext());
this.responseContentTypes.add("text/html"); this.responseContentTypes.add("text/html");
this.locales.add(Locale.ENGLISH); this.locales.add(Locale.ENGLISH);
this.attributes.put(LIFECYCLE_PHASE, getLifecyclePhase());
} }
...@@ -127,6 +135,13 @@ public class MockPortletRequest implements PortletRequest { ...@@ -127,6 +135,13 @@ public class MockPortletRequest implements PortletRequest {
// Lifecycle methods // 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). * Return whether this request is still active (that is, not completed yet).
*/ */
...@@ -363,7 +378,7 @@ public class MockPortletRequest implements PortletRequest { ...@@ -363,7 +378,7 @@ public class MockPortletRequest implements PortletRequest {
return this.parameters.get(name); return this.parameters.get(name);
} }
public Map getParameterMap() { public Map<String, String[]> getParameterMap() {
return Collections.unmodifiableMap(this.parameters); return Collections.unmodifiableMap(this.parameters);
} }
...@@ -459,4 +474,54 @@ public class MockPortletRequest implements PortletRequest { ...@@ -459,4 +474,54 @@ public class MockPortletRequest implements PortletRequest {
return this.serverPort; 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<String, String[]> getPrivateParameterMap() {
if (!this.publicParameterNames.isEmpty()) {
Map<String, String[]> filtered = new LinkedHashMap<String, String[]>();
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<String, String[]> getPublicParameterMap() {
if (!this.publicParameterNames.isEmpty()) {
Map<String, String[]> filtered = new LinkedHashMap<String, String[]>();
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);
}
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -17,9 +17,10 @@ ...@@ -17,9 +17,10 @@
package org.springframework.mock.web.portlet; package org.springframework.mock.web.portlet;
import java.io.IOException; import java.io.IOException;
import javax.portlet.PortletException; import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletRequestDispatcher; import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletResponse;
import javax.portlet.RenderRequest; import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse; import javax.portlet.RenderResponse;
...@@ -53,15 +54,31 @@ public class MockPortletRequestDispatcher implements PortletRequestDispatcher { ...@@ -53,15 +54,31 @@ public class MockPortletRequestDispatcher implements PortletRequestDispatcher {
public void include(RenderRequest request, RenderResponse response) throws PortletException, IOException { 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(request, "Request must not be null");
Assert.notNull(response, "Response must not be null"); Assert.notNull(response, "Response must not be null");
if (!(response instanceof MockRenderResponse)) { if (!(response instanceof MockMimeResponse)) {
throw new IllegalArgumentException("MockPortletRequestDispatcher requires MockRenderResponse"); throw new IllegalArgumentException("MockPortletRequestDispatcher requires MockMimeResponse");
} }
((MockRenderResponse) response).setIncludedUrl(this.url); ((MockMimeResponse) response).setIncludedUrl(this.url);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("MockPortletRequestDispatcher: including URL [" + this.url + "]"); 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 + "]");
}
} }
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,12 +16,20 @@ ...@@ -16,12 +16,20 @@
package org.springframework.mock.web.portlet; package org.springframework.mock.web.portlet;
import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.portlet.PortalContext; import javax.portlet.PortalContext;
import javax.portlet.PortletResponse; 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; import org.springframework.util.Assert;
...@@ -38,6 +46,14 @@ public class MockPortletResponse implements PortletResponse { ...@@ -38,6 +46,14 @@ public class MockPortletResponse implements PortletResponse {
private final Map<String, String[]> properties = new LinkedHashMap<String, String[]>(); private final Map<String, String[]> properties = new LinkedHashMap<String, String[]>();
private String namespace = "";
private final Set<Cookie> cookies = new LinkedHashSet<Cookie>();
private final Map<String, Element[]> xmlProperties = new LinkedHashMap<String, Element[]>();
private Document xmlDocument;
/** /**
* Create a new MockPortletResponse with a default {@link MockPortalContext}. * Create a new MockPortletResponse with a default {@link MockPortalContext}.
...@@ -88,8 +104,8 @@ public class MockPortletResponse implements PortletResponse { ...@@ -88,8 +104,8 @@ public class MockPortletResponse implements PortletResponse {
this.properties.put(key, new String[] {value}); this.properties.put(key, new String[] {value});
} }
public Set getPropertyNames() { public Set<String> getPropertyNames() {
return this.properties.keySet(); return Collections.unmodifiableSet(this.properties.keySet());
} }
public String getProperty(String key) { public String getProperty(String key) {
...@@ -107,4 +123,73 @@ public class MockPortletResponse implements PortletResponse { ...@@ -107,4 +123,73 @@ public class MockPortletResponse implements PortletResponse {
return path; 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<String> 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);
}
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -184,7 +184,23 @@ public class MockPortletSession implements PortletSession { ...@@ -184,7 +184,23 @@ public class MockPortletSession implements PortletSession {
} }
public PortletContext getPortletContext() { public PortletContext getPortletContext() {
return portletContext; return this.portletContext;
}
public Map<String, Object> getAttributeMap() {
return Collections.unmodifiableMap(this.portletAttributes);
}
public Map<String, Object> 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();
}
} }
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,18 +16,10 @@ ...@@ -16,18 +16,10 @@
package org.springframework.mock.web.portlet; 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.Map;
import java.util.Set;
import javax.portlet.PortalContext; import javax.portlet.PortalContext;
import javax.portlet.PortletMode; import javax.portlet.PortletMode;
import javax.portlet.PortletModeException; import javax.portlet.PortletModeException;
import javax.portlet.PortletSecurityException;
import javax.portlet.PortletURL; import javax.portlet.PortletURL;
import javax.portlet.WindowState; import javax.portlet.WindowState;
import javax.portlet.WindowStateException; import javax.portlet.WindowStateException;
...@@ -42,14 +34,12 @@ import org.springframework.util.CollectionUtils; ...@@ -42,14 +34,12 @@ import org.springframework.util.CollectionUtils;
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.0 * @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_RENDER = "render";
public static final String URL_TYPE_ACTION = "action"; public static final String URL_TYPE_ACTION = "action";
private static final String ENCODING = "UTF-8";
private final PortalContext portalContext; private final PortalContext portalContext;
...@@ -59,10 +49,6 @@ public class MockPortletURL implements PortletURL { ...@@ -59,10 +49,6 @@ public class MockPortletURL implements PortletURL {
private PortletMode portletMode; private PortletMode portletMode;
private final Map<String, String[]> parameters = new LinkedHashMap<String, String[]>();
private boolean secure = false;
/** /**
* Create a new MockPortletURL for the given URL type. * Create a new MockPortletURL for the given URL type.
...@@ -90,6 +76,10 @@ public class MockPortletURL implements PortletURL { ...@@ -90,6 +76,10 @@ public class MockPortletURL implements PortletURL {
this.windowState = windowState; this.windowState = windowState;
} }
public WindowState getWindowState() {
return this.windowState;
}
public void setPortletMode(PortletMode portletMode) throws PortletModeException { public void setPortletMode(PortletMode portletMode) throws PortletModeException {
if (!CollectionUtils.contains(this.portalContext.getSupportedPortletModes(), portletMode)) { if (!CollectionUtils.contains(this.portalContext.getSupportedPortletModes(), portletMode)) {
throw new PortletModeException("PortletMode not supported", portletMode); throw new PortletModeException("PortletMode not supported", portletMode);
...@@ -97,77 +87,12 @@ public class MockPortletURL implements PortletURL { ...@@ -97,77 +87,12 @@ public class MockPortletURL implements PortletURL {
this.portletMode = portletMode; this.portletMode = portletMode;
} }
public void setParameter(String key, String value) { public PortletMode getPortletMode() {
Assert.notNull(key, "Parameter key must be null"); return this.portletMode;
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<String> 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) { public void removePublicRenderParameter(String name) {
return this.parameters.get(name); this.parameters.remove(name);
}
public Map<String, String[]> 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;
}
} }
...@@ -183,7 +108,7 @@ public class MockPortletURL implements PortletURL { ...@@ -183,7 +108,7 @@ public class MockPortletURL implements PortletURL {
for (Map.Entry<String, String[]> entry : this.parameters.entrySet()) { for (Map.Entry<String, String[]> entry : this.parameters.entrySet()) {
sb.append(";").append(encodeParameter("param_" + entry.getKey(), entry.getValue())); sb.append(";").append(encodeParameter("param_" + entry.getKey(), entry.getValue()));
} }
return (this.secure ? "https:" : "http:") + return (isSecure() ? "https:" : "http:") +
"//localhost/mockportlet?" + sb.toString(); "//localhost/mockportlet?" + sb.toString();
} }
......
...@@ -3,7 +3,7 @@ Bundle-Name: Spring Web Portlet ...@@ -3,7 +3,7 @@ Bundle-Name: Spring Web Portlet
Bundle-Vendor: SpringSource Bundle-Vendor: SpringSource
Bundle-ManifestVersion: 2 Bundle-ManifestVersion: 2
Import-Template: Import-Template:
javax.portlet.*;version="[1.0.0, 2.0.0)", javax.portlet.*;version="[1.0.0, 3.0.0)",
javax.servlet.*;version="[2.4.0, 3.0.0)", javax.servlet.*;version="[2.4.0, 3.0.0)",
org.apache.commons.fileupload.*;version="[1.2.0, 2.0.0)";resolution:=optional, org.apache.commons.fileupload.*;version="[1.2.0, 2.0.0)";resolution:=optional,
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)", org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
......
...@@ -30,10 +30,12 @@ ...@@ -30,10 +30,12 @@
<orderEntry type="module-library"> <orderEntry type="module-library">
<library> <library>
<CLASSES> <CLASSES>
<root url="jar://$IVY_CACHE$/javax.portlet/com.springsource.javax.portlet/1.0.0/com.springsource.javax.portlet-1.0.0.jar!/" /> <root url="jar://$IVY_CACHE$/javax.portlet/com.springsource.javax.portlet/2.0.0/com.springsource.javax.portlet-2.0.0.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES>
<root url="jar://$IVY_CACHE$/javax.portlet/com.springsource.javax.portlet/2.0.0/com.springsource.javax.portlet-sources-2.0.0.jar!/" />
</SOURCES>
</library> </library>
</orderEntry> </orderEntry>
<orderEntry type="module-library"> <orderEntry type="module-library">
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册