Struts 2 Portlet 2.0 Plugin
Develop JSR286 portlets (portlet 2.0 specification) with this Struts 2 plugin. Experimental!
Source: http://svn.apache.org/repos/asf/struts/sandbox/trunk/struts2-portlet2-plugin/
Download: Latest build
Check http://struts.apache.org/2.x/docs/portlet-plugin.html for documentation for the current JSR168 version of the plugin.
Current feature set
Events
When the Jsr286Dispatcher portlet receives an event, it will look for an action named the same as the event name:
<package name="events" extends="struts-portlet-default"> <action name="name" class="org.apache.struts2.EventAction"> <result type="redirectAction"> <param name="actionName">index</param> <param name="namespace">/view</param> </result> </action> </package>
Example of action creating an event:
public String execute() throws Exception { session.put("firstName", firstName); session.put("lastName", lastName); getActionMessages().add("Name updated"); ((ActionResponse)response).setEvent(new QName("http://com.mycompany/events", "name"), firstName); return SUCCESS; }
Example of action processing an event:
public String execute() throws Exception { EventRequest req = (EventRequest) request; EventResponse res = (EventResponse) response; Event event = req.getEvent(); res.setRenderParameter("lastEvent", (String)event.getValue()); return SUCCESS; }
Resource serving
The s:url tag has been extended with a new portletUrlType. <s:url action="actionCreatingTheResource" portletUrlType="resource"> will create a resource link. Actions responding to these resource urls can for instance use the stream result type to serve images, charts, etc:
<package name="resources" extends="struts-portlet-default"> <action name="image" class="org.apache.struts2.ImageAction"> <result type="stream"> <param name="contentType">image/gif</param> <param name="inputName">imageStream</param> </result> </action> </package>
Comments ( Hide | Add Comment )
|
|
Philipp Anokhin says:Apr 15, 2008 22:15 ( Permalink ) |
|
|
Philipp Anokhin says:Sorry, "We were trying to use the JSR-286 dispatcher, but found that it lacks proper support for render requests" above should read as "We were trying to use the JSR-286 dispatcher, but found that it lacks proper support for resource requests" |
Anonymous says:i can't download latest build. please recheck! thanks |
Anonymous says:The current Shapshot does not work with 2.1.8 java.lang.NoClassDefFoundError: com.opensymphony.xwork2.util.TextUtils |
Anonymous says:The code in subversion should be updated to support 2.1.8 now. |
Anonymous says:Is there any ETA on this plugin's stable release? Please update. |
We were trying to use the JSR-286 dispatcher, but found that it lacks proper support for render requests. Below is a unified patch against struts2-portlet2-plugin for Struts 2.1.0
Index: src/main/java/org/apache/struts2/portlet/result/PortletResult.java =================================================================== RCS file: /wwwroot/repository/struts2-portlet2-plugin/src/main/java/org/apache/struts2/portlet/result/PortletResult.java,v retrieving revision 1.1 diff -u -r1.1 PortletResult.java --- src/main/java/org/apache/struts2/portlet/result/PortletResult.java 10 Apr 2008 03:41:19 -0000 1.1 +++ src/main/java/org/apache/struts2/portlet/result/PortletResult.java 15 Apr 2008 19:55:53 -0000 @@ -28,7 +28,8 @@ import javax.portlet.PortletException; import javax.portlet.PortletMode; import javax.portlet.PortletRequestDispatcher; -import javax.portlet.RenderRequest; +import javax.portlet.PortletRequest; +import javax.portlet.MimeResponse; import javax.portlet.RenderResponse; import javax.portlet.StateAwareResponse; import javax.servlet.ServletContext; @@ -87,8 +88,8 @@ */ public void doExecute(String finalLocation, ActionInvocation actionInvocation) throws Exception { - if (PortletActionContext.isRender()) { - executeRenderResult(finalLocation); + if (PortletActionContext.isRender() || PortletActionContext.isResource()) { + executeMimeResult(finalLocation); } else if (PortletActionContext.isAction() || PortletActionContext.isEvent()) { executeActionResult(finalLocation, actionInvocation); } else { @@ -125,7 +126,8 @@ * @param invocation */ protected void executeActionResult(String finalLocation, ActionInvocation invocation) throws Exception { - LOG.debug("Executing result in Event phase"); + String phase = (PortletActionContext.isEvent()) ? "Event" : "Action"; + LOG.debug("Executing result in "+phase+" phase"); StateAwareResponse res = (StateAwareResponse)PortletActionContext.getResponse(); Map sessionMap = invocation.getInvocationContext().getSession(); LOG.debug("Setting event render parameter: " + finalLocation); @@ -168,38 +170,39 @@ } } - /** - * Executes the render result. - * - * @param finalLocation - * @throws PortletException - * @throws IOException - */ - protected void executeRenderResult(final String finalLocation) throws PortletException, IOException { - LOG.debug("Executing result in Render phase"); - PortletContext ctx = PortletActionContext.getPortletContext(); - RenderRequest req = PortletActionContext.getRenderRequest(); - RenderResponse res = PortletActionContext.getRenderResponse(); - res.setContentType(contentType); - if (TextUtils.stringSet(title)) { - res.setTitle(title); - } - LOG.debug("Location: " + finalLocation); - if (useDispatcherServlet) { - req.setAttribute(DISPATCH_TO, finalLocation); - PortletRequestDispatcher dispatcher = ctx.getNamedDispatcher(dispatcherServletName); - if(dispatcher == null) { - throw new PortletException("Could not locate dispatcher servlet \"" + dispatcherServletName + "\". Please configure it in your web.xml file"); - } - dispatcher.include(req, res); - } else { - PortletRequestDispatcher dispatcher = ctx.getRequestDispatcher(finalLocation); - if (dispatcher == null) { - throw new PortletException("Could not locate dispatcher for '" + finalLocation + "'"); - } - dispatcher.include(req, res); - } - } + /** + * Executes the render result. + * + * @param finalLocation + * @throws PortletException + * @throws IOException + */ + protected void executeMimeResult(final String finalLocation) throws PortletException, IOException { + String phase = (PortletActionContext.isRender()) ? "Render" : "Resource"; + LOG.debug("Executing result in "+phase+" phase"); + PortletContext ctx = PortletActionContext.getPortletContext(); + PortletRequest req = PortletActionContext.getRequest(); + MimeResponse res = (MimeResponse)PortletActionContext.getResponse(); + res.setContentType(contentType); + if (TextUtils.stringSet(title) && res instanceof RenderResponse) { + ((RenderResponse)res).setTitle(title); + } + LOG.debug("Location: " + finalLocation); + if (useDispatcherServlet) { + req.setAttribute(DISPATCH_TO, finalLocation); + PortletRequestDispatcher dispatcher = ctx.getNamedDispatcher(dispatcherServletName); + if(dispatcher == null) { + throw new PortletException("Could not locate dispatcher servlet \"" + dispatcherServletName + "\". Please configure it in your web.xml file"); + } + dispatcher.include(req, res); + } else { + PortletRequestDispatcher dispatcher = ctx.getRequestDispatcher(finalLocation); + if (dispatcher == null) { + throw new PortletException("Could not locate dispatcher for '" + finalLocation + "'"); + } + dispatcher.include(req, res); + } + } /** * Sets the content type. Index: src/main/java/org/apache/struts2/portlet/util/PortletUrlHelper.java =================================================================== RCS file: /wwwroot/repository/struts2-portlet2-plugin/src/main/java/org/apache/struts2/portlet/util/PortletUrlHelper.java,v retrieving revision 1.1 diff -u -r1.1 PortletUrlHelper.java --- src/main/java/org/apache/struts2/portlet/util/PortletUrlHelper.java 10 Apr 2008 03:41:23 -0000 1.1 +++ src/main/java/org/apache/struts2/portlet/util/PortletUrlHelper.java 15 Apr 2008 19:55:53 -0000 @@ -33,8 +33,8 @@ import javax.portlet.PortletMode; import javax.portlet.PortletSecurityException; import javax.portlet.PortletURL; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; +import javax.portlet.PortletRequest; +import javax.portlet.MimeResponse; import javax.portlet.WindowState; import org.apache.struts2.StrutsException; @@ -47,8 +47,8 @@ * Helper class for creating Portlet URLs. Portlet URLs are fundamentally different from regular * servlet URLs since they never target the application itself; all requests go through the portlet * container and must therefore be programatically constructed using the - * {@link javax.portlet.RenderResponse#createActionURL()} and - * {@link javax.portlet.RenderResponse#createRenderURL()} APIs. + * {@link javax.portlet.MimeResponse#createActionURL()} and + * {@link javax.portlet.MimeResponse#createRenderURL()} APIs. * */ public class PortletUrlHelper { @@ -83,13 +83,13 @@ String scheme, String type, String portletMode, String windowState, boolean includeContext, boolean encodeResult) { StringBuffer resultingAction = new StringBuffer(); - RenderRequest request = PortletActionContext.getRenderRequest(); - RenderResponse response = PortletActionContext.getRenderResponse(); + PortletRequest request = PortletActionContext.getRequest(); + MimeResponse response = (MimeResponse)PortletActionContext.getResponse(); LOG.debug("Creating url. Action = " + action + ", Namespace = " + namespace + ", Type = " + type); namespace = prependNamespace(namespace, portletMode); if (!TextUtils.stringSet(portletMode)) { - portletMode = PortletActionContext.getRenderRequest().getPortletMode().toString(); + portletMode = PortletActionContext.getRequest().getPortletMode().toString(); } String result = null; int paramStartIndex = action.indexOf('?'); @@ -170,7 +170,7 @@ */ private static String prependNamespace(String namespace, String portletMode) { StringBuffer sb = new StringBuffer(); - PortletMode mode = PortletActionContext.getRenderRequest().getPortletMode(); + PortletMode mode = PortletActionContext.getRequest().getPortletMode(); if(TextUtils.stringSet(portletMode)) { mode = new PortletMode(portletMode); } @@ -228,8 +228,8 @@ throw new StrutsException("Encoding "+ENCODING+" not found"); } } - RenderResponse resp = PortletActionContext.getRenderResponse(); - RenderRequest req = PortletActionContext.getRenderRequest(); + MimeResponse resp = (MimeResponse)PortletActionContext.getResponse(); + PortletRequest req = PortletActionContext.getRequest(); return resp.encodeURL(req.getContextPath() + sb.toString()); } @@ -261,12 +261,12 @@ /** * Convert the given String to a WindowState object. * - * @param portletReq The RenderRequest. + * @param portletReq The PortletRequest. * @param windowState The WindowState as a String. * @return The WindowState that mathces the <tt>windowState</tt> String, or if * the Sring is blank, the current WindowState. */ - private static WindowState getWindowState(RenderRequest portletReq, + private static WindowState getWindowState(PortletRequest portletReq, String windowState) { WindowState state = portletReq.getWindowState(); if (TextUtils.stringSet(windowState)) { @@ -288,12 +288,12 @@ /** * Convert the given String to a PortletMode object. * - * @param portletReq The RenderRequest. + * @param portletReq The PortletRequest. * @param portletMode The PortletMode as a String. * @return The PortletMode that mathces the <tt>portletMode</tt> String, or if * the Sring is blank, the current PortletMode. */ - private static PortletMode getPortletMode(RenderRequest portletReq, + private static PortletMode getPortletMode(PortletRequest portletReq, String portletMode) { PortletMode mode = portletReq.getPortletMode(); Index: src/main/java/org/apache/struts2/portlet/context/PortletActionContext.java =================================================================== RCS file: /wwwroot/repository/struts2-portlet2-plugin/src/main/java/org/apache/struts2/portlet/context/PortletActionContext.java,v retrieving revision 1.1 diff -u -r1.1 PortletActionContext.java --- src/main/java/org/apache/struts2/portlet/context/PortletActionContext.java 10 Apr 2008 03:41:21 -0000 1.1 +++ src/main/java/org/apache/struts2/portlet/context/PortletActionContext.java 15 Apr 2008 19:55:53 -0000 @@ -164,6 +164,13 @@ } /** + * @return <code>true</code> if the Portlet is executing in the resource phase. + */ + public static boolean isResource() { + return SERVE_RESOURCE_PHASE.equals(getPhase()); + } + + /** * @return The current ActionContext. */ private static ActionContext getContext() {