You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by jo...@apache.org on 2011/06/23 22:18:46 UTC
svn commit: r1139061 [2/5] - in /struts/archive/plugins: ./ src/ src/main/
src/main/java/ src/main/java/org/ src/main/java/org/apache/
src/main/java/org/apache/struts2/
src/main/java/org/apache/struts2/components/
src/main/java/org/apache/struts2/portl...
Added: struts/archive/plugins/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java
URL: http://svn.apache.org/viewvc/struts/archive/plugins/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java?rev=1139061&view=auto
==============================================================================
--- struts/archive/plugins/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java (added)
+++ struts/archive/plugins/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java Thu Jun 23 20:18:43 2011
@@ -0,0 +1,628 @@
+/*
+ * $Id: Jsr168Dispatcher.java 1099157 2011-05-03 17:53:55Z jogep $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.portlet.dispatcher;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.portlet.ActionRequest;
+import javax.portlet.ActionResponse;
+import javax.portlet.GenericPortlet;
+import javax.portlet.PortletConfig;
+import javax.portlet.PortletException;
+import javax.portlet.PortletMode;
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletResponse;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+import javax.portlet.WindowState;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.struts2.StrutsConstants;
+import org.apache.struts2.StrutsException;
+import org.apache.struts2.StrutsStatics;
+import org.apache.struts2.dispatcher.ApplicationMap;
+import org.apache.struts2.dispatcher.Dispatcher;
+import org.apache.struts2.dispatcher.RequestMap;
+import org.apache.struts2.dispatcher.SessionMap;
+import org.apache.struts2.dispatcher.mapper.ActionMapper;
+import org.apache.struts2.dispatcher.mapper.ActionMapping;
+import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
+import org.apache.struts2.portlet.PortletActionConstants;
+import org.apache.struts2.portlet.PortletApplicationMap;
+import org.apache.struts2.portlet.PortletRequestMap;
+import org.apache.struts2.portlet.PortletSessionMap;
+import org.apache.struts2.portlet.context.PortletActionContext;
+import org.apache.struts2.portlet.servlet.PortletServletContext;
+import org.apache.struts2.portlet.servlet.PortletServletRequest;
+import org.apache.struts2.portlet.servlet.PortletServletResponse;
+import org.apache.struts2.util.AttributeMap;
+import org.apache.commons.lang.StringUtils;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionProxy;
+import com.opensymphony.xwork2.ActionProxyFactory;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.inject.Container;
+import com.opensymphony.xwork2.util.FileManager;
+import com.opensymphony.xwork2.util.LocalizedTextUtil;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+
+/**
+ * <!-- START SNIPPET: javadoc -->
+ * <p>
+ * Struts JSR-168 portlet dispatcher. Similar to the WW2 Servlet dispatcher,
+ * but adjusted to a portal environment. The portlet is configured through the <tt>portlet.xml</tt>
+ * descriptor. Examples and descriptions follow below:
+ * </p>
+ * <!-- END SNIPPET: javadoc -->
+ *
+ * @author Nils-Helge Garli
+ * @author Rainer Hermanns
+ *
+ * <p><b>Init parameters</b></p>
+ * <!-- START SNIPPET: params -->
+ * <table class="confluenceTable">
+ * <tr>
+ * <th class="confluenceTh">Name</th>
+ * <th class="confluenceTh">Description</th>
+ * <th class="confluenceTh">Default value</th>
+ * </tr>
+ * <tr>
+ * <td class="confluenceTd">portletNamespace</td><td class="confluenceTd">The namespace for the portlet in the xwork configuration. This
+ * namespace is prepended to all action lookups, and makes it possible to host multiple
+ * portlets in the same portlet application. If this parameter is set, the complete namespace
+ * will be <tt>/portletNamespace/modeNamespace/actionName</tt></td><td class="confluenceTd">The default namespace</td>
+ * </tr>
+ * <tr>
+ * <td class="confluenceTd">viewNamespace</td><td class="confluenceTd">Base namespace in the xwork configuration for the <tt>view</tt> portlet
+ * mode</td><td class="confluenceTd">The default namespace</td>
+ * </tr>
+ * <tr>
+ * <td class="confluenceTd">editNamespace</td><td class="confluenceTd">Base namespace in the xwork configuration for the <tt>edit</tt> portlet
+ * mode</td><td class="confluenceTd">The default namespace</td>
+ * </tr>
+ * <tr>
+ * <td class="confluenceTd">helpNamespace</td><td class="confluenceTd">Base namespace in the xwork configuration for the <tt>help</tt> portlet
+ * mode</td><td class="confluenceTd">The default namespace</td>
+ * </tr>
+ * <tr>
+ * <td class="confluenceTd">defaultViewAction</td><td class="confluenceTd">Default action to invoke in the <tt>view</tt> portlet mode if no action is
+ * specified</td><td class="confluenceTd"><tt>default</tt></td>
+ * </tr>
+ * <tr>
+ * <td class="confluenceTd">defaultEditAction</td><td class="confluenceTd">Default action to invoke in the <tt>edit</tt> portlet mode if no action is
+ * specified</td><td class="confluenceTd"><tt>default</tt></td>
+ * </tr>
+ * <tr>
+ * <td class="confluenceTd">defaultHelpAction</td><td class="confluenceTd">Default action to invoke in the <tt>help</tt> portlet mode if no action is
+ * specified</td><td class="confluenceTd"><tt>default</tt></td>
+ * </tr>
+ * </table>
+ * <!-- END SNIPPET: params -->
+ * <p><b>Example:</b></p>
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ *
+ * <init-param>
+ * <!-- The view mode namespace. Maps to a namespace in the xwork config file -->
+ * <name>viewNamespace</name>
+ * <value>/view</value>
+ * </init-param>
+ * <init-param>
+ * <!-- The default action to invoke in view mode -->
+ * <name>defaultViewAction</name>
+ * <value>index</value>
+ * </init-param>
+ * <init-param>
+ * <!-- The view mode namespace. Maps to a namespace in the xwork config file -->
+ * <name>editNamespace</name>
+ * <value>/edit</value>
+ * </init-param>
+ * <init-param>
+ * <!-- The default action to invoke in view mode -->
+ * <name>defaultEditAction</name>
+ * <value>index</value>
+ * </init-param>
+ * <init-param>
+ * <!-- The view mode namespace. Maps to a namespace in the xwork config file -->
+ * <name>helpNamespace</name>
+ * <value>/help</value>
+ * </init-param>
+ * <init-param>
+ * <!-- The default action to invoke in view mode -->
+ * <name>defaultHelpAction</name>
+ * <value>index</value>
+ * </init-param>
+ *
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ */
+public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics,
+ PortletActionConstants {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Jsr168Dispatcher.class);
+
+ private ActionProxyFactory factory = null;
+
+ private Map<PortletMode,String> modeMap = new HashMap<PortletMode,String>(3);
+
+ private Map<PortletMode,ActionMapping> actionMap = new HashMap<PortletMode,ActionMapping>(3);
+
+ private String portletNamespace = null;
+
+ private Dispatcher dispatcherUtils;
+
+ private ActionMapper actionMapper;
+
+ private Container container;
+
+ /**
+ * Initialize the portlet with the init parameters from <tt>portlet.xml</tt>
+ */
+ public void init(PortletConfig cfg) throws PortletException {
+ super.init(cfg);
+ if (LOG.isDebugEnabled()) LOG.debug("Initializing portlet " + getPortletName());
+
+ Map<String,String> params = new HashMap<String,String>();
+ for (Enumeration e = cfg.getInitParameterNames(); e.hasMoreElements(); ) {
+ String name = (String) e.nextElement();
+ String value = cfg.getInitParameter(name);
+ params.put(name, value);
+ }
+
+ dispatcherUtils = new Dispatcher(new PortletServletContext(cfg.getPortletContext()), params);
+ dispatcherUtils.init();
+
+ // For testability
+ if (factory == null) {
+ factory = dispatcherUtils.getConfigurationManager().getConfiguration().getContainer().getInstance(ActionProxyFactory.class);
+ }
+ portletNamespace = cfg.getInitParameter("portletNamespace");
+ if (LOG.isDebugEnabled()) LOG.debug("PortletNamespace: " + portletNamespace);
+ parseModeConfig(actionMap, cfg, PortletMode.VIEW, "viewNamespace",
+ "defaultViewAction");
+ parseModeConfig(actionMap, cfg, PortletMode.EDIT, "editNamespace",
+ "defaultEditAction");
+ parseModeConfig(actionMap, cfg, PortletMode.HELP, "helpNamespace",
+ "defaultHelpAction");
+ parseModeConfig(actionMap, cfg, new PortletMode("config"), "configNamespace",
+ "defaultConfigAction");
+ parseModeConfig(actionMap, cfg, new PortletMode("about"), "aboutNamespace",
+ "defaultAboutAction");
+ parseModeConfig(actionMap, cfg, new PortletMode("print"), "printNamespace",
+ "defaultPrintAction");
+ parseModeConfig(actionMap, cfg, new PortletMode("preview"), "previewNamespace",
+ "defaultPreviewAction");
+ parseModeConfig(actionMap, cfg, new PortletMode("edit_defaults"),
+ "editDefaultsNamespace", "defaultEditDefaultsAction");
+ if (StringUtils.isEmpty(portletNamespace)) {
+ portletNamespace = "";
+ }
+ LocalizedTextUtil
+ .addDefaultResourceBundle("org/apache/struts2/struts-messages");
+
+ container = dispatcherUtils.getContainer();
+ //check for configuration reloading
+ if ("true".equalsIgnoreCase(container.getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD))) {
+ FileManager.setReloadingConfigs(true);
+ }
+
+ actionMapper = container.getInstance(ActionMapper.class);
+ }
+
+ /**
+ * Parse the mode to namespace mappings configured in portlet.xml
+ * @param actionMap The map with mode <-> default action mapping.
+ * @param portletConfig The PortletConfig.
+ * @param portletMode The PortletMode.
+ * @param nameSpaceParam Name of the init parameter where the namespace for the mode
+ * is configured.
+ * @param defaultActionParam Name of the init parameter where the default action to
+ * execute for the mode is configured.
+ */
+ void parseModeConfig(Map<PortletMode, ActionMapping> actionMap, PortletConfig portletConfig,
+ PortletMode portletMode, String nameSpaceParam,
+ String defaultActionParam) {
+ String namespace = portletConfig.getInitParameter(nameSpaceParam);
+ if (StringUtils.isEmpty(namespace)) {
+ namespace = "";
+ }
+ modeMap.put(portletMode, namespace);
+ String defaultAction = portletConfig
+ .getInitParameter(defaultActionParam);
+ String method = null;
+ if (StringUtils.isEmpty(defaultAction)) {
+ defaultAction = DEFAULT_ACTION_NAME;
+ }
+ if(defaultAction.indexOf('!') >= 0) {
+ method = defaultAction.substring(defaultAction.indexOf('!') + 1);
+ defaultAction = defaultAction.substring(0, defaultAction.indexOf('!'));
+ }
+ StringBuffer fullPath = new StringBuffer();
+ if (StringUtils.isNotEmpty(portletNamespace)) {
+ fullPath.append(portletNamespace);
+ }
+ if (StringUtils.isNotEmpty(namespace)) {
+ fullPath.append(namespace).append("/");
+ } else {
+ fullPath.append("/");
+ }
+ fullPath.append(defaultAction);
+ ActionMapping mapping = new ActionMapping();
+ mapping.setName(getActionName(fullPath.toString()));
+ mapping.setNamespace(getNamespace(fullPath.toString()));
+ if(method != null) {
+ mapping.setMethod(method);
+ }
+ actionMap.put(portletMode, mapping);
+ }
+
+ /**
+ * Service an action from the <tt>event</tt> phase.
+ *
+ * @see javax.portlet.Portlet#processAction(javax.portlet.ActionRequest,
+ * javax.portlet.ActionResponse)
+ */
+ public void processAction(ActionRequest request, ActionResponse response)
+ throws PortletException, IOException {
+ if (LOG.isDebugEnabled()) LOG.debug("Entering processAction");
+ resetActionContext();
+ try {
+ serviceAction(request, response, getRequestMap(request), getParameterMap(request),
+ getSessionMap(request), getApplicationMap(),
+ portletNamespace, EVENT_PHASE);
+ if (LOG.isDebugEnabled()) LOG.debug("Leaving processAction");
+ } finally {
+ ActionContext.setContext(null);
+ }
+ }
+
+ /**
+ * Service an action from the <tt>render</tt> phase.
+ *
+ * @see javax.portlet.Portlet#render(javax.portlet.RenderRequest,
+ * javax.portlet.RenderResponse)
+ */
+ public void render(RenderRequest request, RenderResponse response)
+ throws PortletException, IOException {
+
+ if (LOG.isDebugEnabled()) LOG.debug("Entering render");
+ resetActionContext();
+ response.setTitle(getTitle(request));
+ if(!request.getWindowState().equals(WindowState.MINIMIZED)) {
+ try {
+ // Check to see if an event set the render to be included directly
+ serviceAction(request, response, getRequestMap(request), getParameterMap(request),
+ getSessionMap(request), getApplicationMap(),
+ portletNamespace, RENDER_PHASE);
+ if (LOG.isDebugEnabled()) LOG.debug("Leaving render");
+ } finally {
+ resetActionContext();
+ }
+ }
+ }
+
+ /**
+ * Reset the action context.
+ */
+ private void resetActionContext() {
+ ActionContext.setContext(null);
+ }
+
+ /**
+ * Merges all application and portlet attributes into a single
+ * <tt>HashMap</tt> to represent the entire <tt>Action</tt> context.
+ *
+ * @param requestMap a Map of all request attributes.
+ * @param parameterMap a Map of all request parameters.
+ * @param sessionMap a Map of all session attributes.
+ * @param applicationMap a Map of all servlet context attributes.
+ * @param request the PortletRequest object.
+ * @param response the PortletResponse object.
+ * @param portletConfig the PortletConfig object.
+ * @param phase The portlet phase (render or action, see
+ * {@link PortletActionConstants})
+ * @return a HashMap representing the <tt>Action</tt> context.
+ */
+ public HashMap<String, Object> createContextMap(Map<String, Object> requestMap, Map<String, String[]> parameterMap,
+ Map<String, Object> sessionMap, Map<String, Object> applicationMap, PortletRequest request,
+ PortletResponse response, HttpServletRequest servletRequest, HttpServletResponse servletResponse, ServletContext servletContext, PortletConfig portletConfig, Integer phase) throws IOException {
+
+ // TODO Must put http request/response objects into map for use with
+ container.inject(servletRequest);
+
+ // ServletActionContext
+ HashMap<String, Object> extraContext = new HashMap<String, Object>();
+ // The dummy servlet objects. Eases reuse of existing interceptors that uses the servlet objects.
+ extraContext.put(StrutsStatics.HTTP_REQUEST, servletRequest);
+ extraContext.put(StrutsStatics.HTTP_RESPONSE, servletResponse);
+ extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
+ // End dummy servlet objects
+ extraContext.put(ActionContext.PARAMETERS, parameterMap);
+ extraContext.put(ActionContext.SESSION, sessionMap);
+ extraContext.put(ActionContext.APPLICATION, applicationMap);
+
+ String defaultLocale = dispatcherUtils.getContainer().getInstance(String.class, StrutsConstants.STRUTS_LOCALE);
+ Locale locale = null;
+ if (defaultLocale != null) {
+ locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
+ } else {
+ locale = request.getLocale();
+ }
+ extraContext.put(ActionContext.LOCALE, locale);
+
+ extraContext.put(StrutsStatics.STRUTS_PORTLET_CONTEXT, getPortletContext());
+ extraContext.put(REQUEST, request);
+ extraContext.put(RESPONSE, response);
+ extraContext.put(PORTLET_CONFIG, portletConfig);
+ extraContext.put(PORTLET_NAMESPACE, portletNamespace);
+ extraContext.put(DEFAULT_ACTION_FOR_MODE, actionMap.get(request.getPortletMode()));
+ // helpers to get access to request/session/application scope
+ extraContext.put("request", requestMap);
+ extraContext.put("session", sessionMap);
+ extraContext.put("application", applicationMap);
+ extraContext.put("parameters", parameterMap);
+ extraContext.put(MODE_NAMESPACE_MAP, modeMap);
+
+ extraContext.put(PHASE, phase);
+
+ AttributeMap attrMap = new AttributeMap(extraContext);
+ extraContext.put("attr", attrMap);
+
+ return extraContext;
+ }
+
+ /**
+ * Loads the action and executes it. This method first creates the action
+ * context from the given parameters then loads an <tt>ActionProxy</tt>
+ * from the given action name and namespace. After that, the action is
+ * executed and output channels throught the response object.
+ *
+ * @param request the HttpServletRequest object.
+ * @param response the HttpServletResponse object.
+ * @param requestMap a Map of request attributes.
+ * @param parameterMap a Map of request parameters.
+ * @param sessionMap a Map of all session attributes.
+ * @param applicationMap a Map of all application attributes.
+ * @param portletNamespace the namespace or context of the action.
+ * @param phase The portlet phase (render or action, see
+ * {@link PortletActionConstants})
+ */
+ public void serviceAction(PortletRequest request, PortletResponse response, Map<String, Object> requestMap, Map<String, String[]> parameterMap,
+ Map<String, Object> sessionMap, Map<String, Object> applicationMap, String portletNamespace,
+ Integer phase) throws PortletException {
+ if (LOG.isDebugEnabled()) LOG.debug("serviceAction");
+ Dispatcher.setInstance(dispatcherUtils);
+ String actionName = null;
+ String namespace = null;
+ try {
+ ServletContext servletContext = new PortletServletContext(getPortletContext());
+ HttpServletRequest servletRequest = new PortletServletRequest(request, getPortletContext());
+ HttpServletResponse servletResponse = new PortletServletResponse(response);
+ if(EVENT_PHASE.equals(phase)) {
+ servletRequest = dispatcherUtils.wrapRequest(servletRequest, servletContext);
+ if(servletRequest instanceof MultiPartRequestWrapper) {
+ // Multipart request. Request parameters are encoded in the multipart data,
+ // so we need to manually add them to the parameter map.
+ parameterMap.putAll(servletRequest.getParameterMap());
+ }
+ }
+ container.inject(servletRequest);
+ ActionMapping mapping = getActionMapping(request, servletRequest);
+ actionName = mapping.getName();
+ namespace = mapping.getNamespace();
+ HashMap<String, Object> extraContext = createContextMap(requestMap, parameterMap,
+ sessionMap, applicationMap, request, response, servletRequest, servletResponse,
+ servletContext, getPortletConfig(), phase);
+ extraContext.put(PortletActionConstants.ACTION_MAPPING, mapping);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Creating action proxy for name = " + actionName + ", namespace = " + namespace);
+ }
+ ActionProxy proxy = factory.createActionProxy(namespace,
+ actionName, mapping.getMethod(), extraContext);
+ request.setAttribute("struts.valueStack", proxy.getInvocation()
+ .getStack());
+ proxy.execute();
+ } catch (ConfigurationException e) {
+ LOG.error("Could not find action", e);
+ throw new PortletException("Could not find action " + actionName, e);
+ } catch (Exception e) {
+ LOG.error("Could not execute action", e);
+ throw new PortletException("Error executing action " + actionName,
+ e);
+ } finally {
+ Dispatcher.setInstance(null);
+ }
+ }
+
+ /**
+ * Returns a Map of all application attributes. Copies all attributes from
+ * the {@link PortletActionContext}into an {@link ApplicationMap}.
+ *
+ * @return a Map of all application attributes.
+ */
+ protected Map getApplicationMap() {
+ return new PortletApplicationMap(getPortletContext());
+ }
+
+ /**
+ * Gets the namespace of the action from the request. The namespace is the
+ * same as the portlet mode. E.g, view mode is mapped to namespace
+ * <code>view</code>, and edit mode is mapped to the namespace
+ * <code>edit</code>
+ *
+ * @param request the PortletRequest object.
+ * @return the namespace of the action.
+ */
+ protected ActionMapping getActionMapping(final PortletRequest portletRequest, final HttpServletRequest servletRequest) {
+ ActionMapping mapping = null;
+ String actionPath = null;
+ if (resetAction(portletRequest)) {
+ mapping = (ActionMapping) actionMap.get(portletRequest.getPortletMode());
+ } else {
+ actionPath = servletRequest.getParameter(ACTION_PARAM);
+ if (StringUtils.isEmpty(actionPath)) {
+ mapping = (ActionMapping) actionMap.get(portletRequest
+ .getPortletMode());
+ } else {
+
+ // Use the usual action mapper, but it is expecting an action extension
+ // on the uri, so we add the default one, which should be ok as the
+ // portlet is a portlet first, a servlet second
+ mapping = actionMapper.getMapping(servletRequest, dispatcherUtils.getConfigurationManager());
+ }
+ }
+
+ if (mapping == null) {
+ throw new StrutsException("Unable to locate action mapping for request, probably due to " +
+ "an invalid action path: "+actionPath);
+ }
+ return mapping;
+ }
+
+ /**
+ * Get the namespace part of the action path.
+ * @param actionPath Full path to action
+ * @return The namespace part.
+ */
+ String getNamespace(String actionPath) {
+ int idx = actionPath.lastIndexOf('/');
+ String namespace = "";
+ if (idx >= 0) {
+ namespace = actionPath.substring(0, idx);
+ }
+ return namespace;
+ }
+
+ /**
+ * Get the action name part of the action path.
+ * @param actionPath Full path to action
+ * @return The action name.
+ */
+ String getActionName(String actionPath) {
+ int idx = actionPath.lastIndexOf('/');
+ String action = actionPath;
+ if (idx >= 0) {
+ action = actionPath.substring(idx + 1);
+ }
+ return action;
+ }
+
+ /**
+ * Returns a Map of all request parameters. This implementation just calls
+ * {@link PortletRequest#getParameterMap()}.
+ *
+ * @param request the PortletRequest object.
+ * @return a Map of all request parameters.
+ * @throws IOException if an exception occurs while retrieving the parameter
+ * map.
+ */
+ protected Map<String, String[]> getParameterMap(PortletRequest request) throws IOException {
+ return new HashMap<String, String[]>(request.getParameterMap());
+ }
+
+ /**
+ * Returns a Map of all request attributes. The default implementation is to
+ * wrap the request in a {@link RequestMap}. Override this method to
+ * customize how request attributes are mapped.
+ *
+ * @param request the PortletRequest object.
+ * @return a Map of all request attributes.
+ */
+ protected Map getRequestMap(PortletRequest request) {
+ return new PortletRequestMap(request);
+ }
+
+ /**
+ * Returns a Map of all session attributes. The default implementation is to
+ * wrap the reqeust in a {@link SessionMap}. Override this method to
+ * customize how session attributes are mapped.
+ *
+ * @param request the PortletRequest object.
+ * @return a Map of all session attributes.
+ */
+ protected Map getSessionMap(PortletRequest request) {
+ return new PortletSessionMap(request);
+ }
+
+ /**
+ * Convenience method to ease testing.
+ * @param factory
+ */
+ protected void setActionProxyFactory(ActionProxyFactory factory) {
+ this.factory = factory;
+ }
+
+ /**
+ * Check to see if the action parameter is valid for the current portlet mode. If the portlet
+ * mode has been changed with the portal widgets, the action name is invalid, since the
+ * action name belongs to the previous executing portlet mode. If this method evaluates to
+ * <code>true</code> the <code>default<Mode>Action</code> is used instead.
+ * @param request The portlet request.
+ * @return <code>true</code> if the action should be reset.
+ */
+ private boolean resetAction(PortletRequest request) {
+ boolean reset = false;
+ Map paramMap = request.getParameterMap();
+ String[] modeParam = (String[]) paramMap.get(MODE_PARAM);
+ if (modeParam != null && modeParam.length == 1) {
+ String originatingMode = modeParam[0];
+ String currentMode = request.getPortletMode().toString();
+ if (!currentMode.equals(originatingMode)) {
+ reset = true;
+ }
+ }
+ if(reset) {
+ request.setAttribute(ACTION_RESET, Boolean.TRUE);
+ }
+ else {
+ request.setAttribute(ACTION_RESET, Boolean.FALSE);
+ }
+ return reset;
+ }
+
+ public void destroy() {
+ if (dispatcherUtils == null) {
+ if (LOG.isWarnEnabled()) {
+ LOG.warn("something is seriously wrong, DispatcherUtil is not initialized (null) ");
+ }
+ } else {
+ dispatcherUtils.cleanup();
+ }
+ }
+
+ /**
+ * @param actionMapper the actionMapper to set
+ */
+ public void setActionMapper(ActionMapper actionMapper) {
+ this.actionMapper = actionMapper;
+ }
+
+}
Added: struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletAwareInterceptor.java
URL: http://svn.apache.org/viewvc/struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletAwareInterceptor.java?rev=1139061&view=auto
==============================================================================
--- struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletAwareInterceptor.java (added)
+++ struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletAwareInterceptor.java Thu Jun 23 20:18:43 2011
@@ -0,0 +1,92 @@
+/*
+ * $Id: PortletAwareInterceptor.java 1099157 2011-05-03 17:53:55Z jogep $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.portlet.interceptor;
+
+import javax.portlet.PortletConfig;
+import javax.portlet.PortletContext;
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletResponse;
+
+import org.apache.struts2.StrutsStatics;
+import org.apache.struts2.interceptor.PrincipalAware;
+import org.apache.struts2.portlet.PortletActionConstants;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+
+public class PortletAwareInterceptor extends AbstractInterceptor implements PortletActionConstants, StrutsStatics {
+
+ private static final long serialVersionUID = 2476509721059587700L;
+
+ private static final Logger LOG = LoggerFactory.getLogger(PortletAwareInterceptor.class);
+
+ /**
+ * Sets action properties based on the interfaces an action implements. Things like application properties,
+ * parameters, session attributes, etc are set based on the implementing interface.
+ *
+ * @param invocation an encapsulation of the action execution state.
+ * @throws Exception if an error occurs when setting action properties.
+ */
+ public String intercept(ActionInvocation invocation) throws Exception {
+ final Object action = invocation.getAction();
+ final ActionContext context = invocation.getInvocationContext();
+
+ if (action instanceof PortletRequestAware) {
+ PortletRequest request = (PortletRequest) context.get(REQUEST);
+ ((PortletRequestAware) action).setPortletRequest(request);
+ }
+
+ if (action instanceof PortletResponseAware) {
+ PortletResponse response = (PortletResponse) context.get(RESPONSE);
+ ((PortletResponseAware) action).setPortletResponse(response);
+ }
+ if (action instanceof PrincipalAware) {
+ PortletRequest request = (PortletRequest) context.get(REQUEST);
+ ((PrincipalAware) action).setPrincipalProxy(new PortletPrincipalProxy(request));
+ }
+ if (action instanceof PortletContextAware) {
+ PortletContext portletContext = (PortletContext) context.get(STRUTS_PORTLET_CONTEXT);
+ ((PortletContextAware) action).setPortletContext(portletContext);
+ }
+ if (action instanceof PortletConfigAware) {
+ PortletConfig portletConfig = (PortletConfig)context.get(PORTLET_CONFIG);
+ ((PortletConfigAware) action).setPortletConfig(portletConfig);
+ }
+ if (action instanceof PortletPreferencesAware) {
+ PortletRequest request = (PortletRequest) context.get(REQUEST);
+
+ // Check if running in a servlet environment
+ if (request == null) {
+ if (LOG.isWarnEnabled()) {
+ LOG.warn("This portlet preferences implementation should only be used during development");
+ }
+ ((PortletPreferencesAware)action).setPortletPreferences(new ServletPortletPreferences(ActionContext.getContext().getSession()));
+ } else {
+ ((PortletPreferencesAware)action).setPortletPreferences(request.getPreferences());
+ }
+ }
+ return invocation.invoke();
+ }
+}
Added: struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletConfigAware.java
URL: http://svn.apache.org/viewvc/struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletConfigAware.java?rev=1139061&view=auto
==============================================================================
--- struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletConfigAware.java (added)
+++ struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletConfigAware.java Thu Jun 23 20:18:43 2011
@@ -0,0 +1,34 @@
+/*
+ * $Id: $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.portlet.interceptor;
+
+import javax.portlet.PortletConfig;
+
+
+/**
+ * Actions that wants a reference to the PortletConfig object can
+ * implement this interface.
+ *
+ */
+public interface PortletConfigAware {
+
+ void setPortletConfig(PortletConfig portletConfig);
+}
Added: struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletContextAware.java
URL: http://svn.apache.org/viewvc/struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletContextAware.java?rev=1139061&view=auto
==============================================================================
--- struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletContextAware.java (added)
+++ struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletContextAware.java Thu Jun 23 20:18:43 2011
@@ -0,0 +1,30 @@
+/*
+ * $Id: PortletContextAware.java 651946 2008-04-27 13:41:38Z apetrelli $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.portlet.interceptor;
+
+import javax.portlet.PortletContext;
+
+public interface PortletContextAware {
+
+ void setPortletContext(PortletContext portletContext);
+
+}
Added: struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletPreferencesAware.java
URL: http://svn.apache.org/viewvc/struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletPreferencesAware.java?rev=1139061&view=auto
==============================================================================
--- struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletPreferencesAware.java (added)
+++ struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletPreferencesAware.java Thu Jun 23 20:18:43 2011
@@ -0,0 +1,40 @@
+/*
+ * $Id: PortletPreferencesAware.java 651946 2008-04-27 13:41:38Z apetrelli $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.portlet.interceptor;
+
+import javax.portlet.PortletPreferences;
+
+
+/**
+ * All Actions that want to have access to the portlet preferences should
+ * implement this interface. If running in a servlet environment, an
+ * appropriate testing implementation will be provided.
+ */
+public interface PortletPreferencesAware {
+
+ /**
+ * Sets the HTTP request object in implementing classes.
+ *
+ * @param request the HTTP request.
+ */
+ public void setPortletPreferences(PortletPreferences prefs);
+}
Added: struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletPrincipalProxy.java
URL: http://svn.apache.org/viewvc/struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletPrincipalProxy.java?rev=1139061&view=auto
==============================================================================
--- struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletPrincipalProxy.java (added)
+++ struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletPrincipalProxy.java Thu Jun 23 20:18:43 2011
@@ -0,0 +1,94 @@
+/*
+ * $Id: PortletPrincipalProxy.java 651946 2008-04-27 13:41:38Z apetrelli $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.portlet.interceptor;
+
+import org.apache.struts2.interceptor.PrincipalProxy;
+
+import javax.portlet.PortletRequest;
+import javax.servlet.http.HttpServletRequest;
+import java.security.Principal;
+
+/**
+ * PrincipalProxy implementation for using PortletRequest Principal related methods.
+ */
+public class PortletPrincipalProxy implements PrincipalProxy {
+
+ private PortletRequest request;
+
+ /**
+ * Constructs a proxy
+ *
+ * @param request The underlying request
+ */
+ public PortletPrincipalProxy(PortletRequest request) {
+ this.request = request;
+ }
+
+ /**
+ * True if the user is in the given role
+ *
+ * @param role The role
+ * @return True if the user is in that role
+ */
+ public boolean isUserInRole(String role) {
+ return request.isUserInRole(role);
+ }
+
+ /**
+ * Gets the user principal
+ *
+ * @return The principal
+ */
+ public Principal getUserPrincipal() {
+ return request.getUserPrincipal();
+ }
+
+ /**
+ * Gets the user id
+ *
+ * @return The user id
+ */
+ public String getRemoteUser() {
+ return request.getRemoteUser();
+ }
+
+ /**
+ * Is the request using https?
+ *
+ * @return True if using https
+ */
+ public boolean isRequestSecure() {
+ return request.isSecure();
+ }
+
+ /**
+ * Gets the request.
+ *
+ * @return The request
+ * @throws UnsupportedOperationException not supported in this implementation.
+ * @deprecated To obtain the HttpServletRequest in your action, use
+ * {@link org.apache.struts2.servlet.ServletRequestAware}, since this method will be dropped in future.
+ */
+ public HttpServletRequest getRequest() {
+ throw new UnsupportedOperationException("Usage of getRequest() method is deprecadet and not supported for this implementation");
+ }
+}
Added: struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletRequestAware.java
URL: http://svn.apache.org/viewvc/struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletRequestAware.java?rev=1139061&view=auto
==============================================================================
--- struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletRequestAware.java (added)
+++ struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletRequestAware.java Thu Jun 23 20:18:43 2011
@@ -0,0 +1,30 @@
+/*
+ * $Id: PortletRequestAware.java 651946 2008-04-27 13:41:38Z apetrelli $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.portlet.interceptor;
+
+import javax.portlet.PortletRequest;
+
+public interface PortletRequestAware {
+
+ void setPortletRequest(PortletRequest request);
+
+}
Added: struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletResponseAware.java
URL: http://svn.apache.org/viewvc/struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletResponseAware.java?rev=1139061&view=auto
==============================================================================
--- struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletResponseAware.java (added)
+++ struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletResponseAware.java Thu Jun 23 20:18:43 2011
@@ -0,0 +1,30 @@
+/*
+ * $Id: PortletResponseAware.java 651946 2008-04-27 13:41:38Z apetrelli $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.portlet.interceptor;
+
+import javax.portlet.PortletResponse;
+
+public interface PortletResponseAware {
+
+ void setPortletResponse(PortletResponse response);
+
+}
Added: struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletStateInterceptor.java
URL: http://svn.apache.org/viewvc/struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletStateInterceptor.java?rev=1139061&view=auto
==============================================================================
--- struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletStateInterceptor.java (added)
+++ struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/PortletStateInterceptor.java Thu Jun 23 20:18:43 2011
@@ -0,0 +1,95 @@
+/*
+ * $Id: PortletStateInterceptor.java 1076544 2011-03-03 07:19:37Z lukaszlenart $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.portlet.interceptor;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
+import com.opensymphony.xwork2.util.CompoundRoot;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+import org.apache.commons.lang.StringUtils;
+import org.apache.struts2.portlet.PortletActionConstants;
+import org.apache.struts2.portlet.dispatcher.DirectRenderFromEventAction;
+
+import javax.portlet.ActionResponse;
+import javax.portlet.RenderRequest;
+import java.util.Map;
+
+public class PortletStateInterceptor extends AbstractInterceptor implements PortletActionConstants {
+
+ private final static Logger LOG = LoggerFactory.getLogger(PortletStateInterceptor.class);
+
+ private static final long serialVersionUID = 6138452063353911784L;
+
+ @Override
+ public String intercept(ActionInvocation invocation) throws Exception {
+ Integer phase = (Integer) invocation.getInvocationContext().get(PHASE);
+ if (RENDER_PHASE.equals(phase)) {
+ restoreStack(invocation);
+ return invocation.invoke();
+ } else if (EVENT_PHASE.equals(phase)) {
+ try {
+ return invocation.invoke();
+ } finally {
+ saveStack(invocation);
+ }
+ } else {
+ return invocation.invoke();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void saveStack(ActionInvocation invocation) {
+ Map session = invocation.getInvocationContext().getSession();
+ session.put(STACK_FROM_EVENT_PHASE, invocation.getStack());
+ ActionResponse actionResponse = (ActionResponse) invocation.getInvocationContext().get(RESPONSE);
+ actionResponse.setRenderParameter(EVENT_ACTION, "true");
+ }
+
+ @SuppressWarnings("unchecked")
+ private void restoreStack(ActionInvocation invocation) {
+ RenderRequest request = (RenderRequest) invocation.getInvocationContext().get(REQUEST);
+ if (StringUtils.isNotEmpty(request.getParameter(EVENT_ACTION))) {
+ if(!isProperPrg(invocation)) {
+ if (LOG.isDebugEnabled()) LOG.debug("Restoring value stack from event phase");
+ ValueStack oldStack = (ValueStack) invocation.getInvocationContext().getSession().get(
+ STACK_FROM_EVENT_PHASE);
+ if (oldStack != null) {
+ CompoundRoot oldRoot = oldStack.getRoot();
+ ValueStack currentStack = invocation.getStack();
+ CompoundRoot root = currentStack.getRoot();
+ root.addAll(0, oldRoot);
+ if (LOG.isDebugEnabled()) LOG.debug("Restored stack");
+ }
+ }
+ else {
+ if (LOG.isDebugEnabled()) LOG.debug("Won't restore stack from event phase since it's a proper PRG request");
+ }
+ }
+ }
+
+ private boolean isProperPrg(ActionInvocation invocation) {
+ return !(invocation.getAction() instanceof DirectRenderFromEventAction);
+ }
+
+}
Added: struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/ServletPortletPreferences.java
URL: http://svn.apache.org/viewvc/struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/ServletPortletPreferences.java?rev=1139061&view=auto
==============================================================================
--- struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/ServletPortletPreferences.java (added)
+++ struts/archive/plugins/src/main/java/org/apache/struts2/portlet/interceptor/ServletPortletPreferences.java Thu Jun 23 20:18:43 2011
@@ -0,0 +1,96 @@
+/*
+ * $Id: ServletPortletPreferences.java 651946 2008-04-27 13:41:38Z apetrelli $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.portlet.interceptor;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.portlet.PortletPreferences;
+import javax.portlet.ReadOnlyException;
+import javax.portlet.ValidatorException;
+
+/**
+ * Simple portlet preferences implementation that uses a map in the Session
+ * as storage.
+ */
+public class ServletPortletPreferences implements PortletPreferences {
+
+ private Map session;
+ private String PREFERENCES_KEY = "_portlet-preferences";
+
+ public ServletPortletPreferences(Map session) {
+ this.session = session;
+ }
+
+ public Map getMap() {
+ Map map = (Map) session.get(PREFERENCES_KEY);
+ if (map == null) {
+ map = new HashMap();
+ session.put(PREFERENCES_KEY, map);
+ }
+ return map;
+ }
+
+ public Enumeration getNames() {
+ return new Vector(getMap().keySet()).elements();
+ }
+
+ public String getValue(String key, String def) {
+ String val = (String) getMap().get(key);
+ if (val == null) {
+ val = def;
+ }
+ return val;
+ }
+
+ public String[] getValues(String key, String[] def) {
+ String[] val = (String[]) getMap().get(key);
+ if (val == null) {
+ val = def;
+ }
+ return val;
+ }
+
+ public boolean isReadOnly(String arg0) {
+ return false;
+ }
+
+ public void reset(String arg0) throws ReadOnlyException {
+ session.put(PREFERENCES_KEY, new HashMap());
+ }
+
+ public void setValue(String key, String value) throws ReadOnlyException {
+ getMap().put(key, value);
+ }
+
+ public void setValues(String key, String[] value) throws ReadOnlyException {
+ getMap().put(key, value);
+ }
+
+ public void store() throws IOException, ValidatorException {
+
+ }
+
+}
Added: struts/archive/plugins/src/main/java/org/apache/struts2/portlet/result/PortletActionRedirectResult.java
URL: http://svn.apache.org/viewvc/struts/archive/plugins/src/main/java/org/apache/struts2/portlet/result/PortletActionRedirectResult.java?rev=1139061&view=auto
==============================================================================
--- struts/archive/plugins/src/main/java/org/apache/struts2/portlet/result/PortletActionRedirectResult.java (added)
+++ struts/archive/plugins/src/main/java/org/apache/struts2/portlet/result/PortletActionRedirectResult.java Thu Jun 23 20:18:43 2011
@@ -0,0 +1,269 @@
+/*
+ * $Id: PortletActionRedirectResult.java 833239 2009-11-05 23:46:50Z rgielen $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.portlet.result;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.portlet.PortletMode;
+
+import org.apache.struts2.dispatcher.ServletActionRedirectResult;
+import org.apache.struts2.dispatcher.mapper.ActionMapper;
+import org.apache.struts2.dispatcher.mapper.ActionMapping;
+import org.apache.struts2.portlet.PortletActionConstants;
+import org.apache.struts2.views.util.UrlHelper;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.util.reflection.ReflectionExceptionHandler;
+import com.opensymphony.xwork2.util.reflection.ReflectionException;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+import com.opensymphony.xwork2.config.entities.ResultConfig;
+import com.opensymphony.xwork2.inject.Inject;
+
+/**
+ *
+ * Portlet modification of the {@link ServletActionRedirectResult}.
+ *
+ * <!-- START SNIPPET: description -->
+ *
+ * This result uses the {@link ActionMapper} provided by the
+ * {@link ActionMapperFactory} to instruct the render phase to invoke the
+ * specified action and (optional) namespace. This is better than the
+ * {@link PortletResult} because it does not require you to encode the URL
+ * patterns processed by the {@link ActionMapper} in to your struts.xml
+ * configuration files. This means you can change your URL patterns at any point
+ * and your application will still work. It is strongly recommended that if you
+ * are redirecting to another action, you use this result rather than the
+ * standard redirect result.
+ *
+ * See examples below for an example of how request parameters could be passed
+ * in.
+ *
+ * <!-- END SNIPPET: description -->
+ *
+ * <b>This result type takes the following parameters:</b>
+ *
+ * <!-- START SNIPPET: params -->
+ *
+ * <ul>
+ *
+ * <li><b>actionName (default)</b> - the name of the action that will be
+ * redirect to</li>
+ *
+ * <li><b>namespace</b> - used to determine which namespace the action is in
+ * that we're redirecting to . If namespace is null, this defaults to the
+ * current namespace</li>
+ *
+ * </ul>
+ *
+ * <!-- END SNIPPET: params -->
+ *
+ * <b>Example:</b>
+ *
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * <package name="public" extends="struts-default">
+ * <action name="login" class="...">
+ * <!-- Redirect to another namespace -->
+ * <result type="redirectAction">
+ * <param name="actionName">dashboard</param>
+ * <param name="namespace">/secure</param>
+ * </result>
+ * </action>
+ * </package>
+ *
+ * <package name="secure" extends="struts-default" namespace="/secure">
+ * <-- Redirect to an action in the same namespace -->
+ * <action name="dashboard" class="...">
+ * <result>dashboard.jsp</result>
+ * <result name="error" type="redirectAction">error</result>
+ * </action>
+ *
+ * <action name="error" class="...">
+ * <result>error.jsp</result>
+ * </action>
+ * </package>
+ *
+ * <package name="passingRequestParameters" extends="struts-default" namespace="/passingRequestParameters">
+ * <-- Pass parameters (reportType, width and height) -->
+ * <!--
+ * The redirectAction url generated will be :
+ * /genReport/generateReport.action?reportType=pie&width=100&height=100
+ * -->
+ * <action name="gatherReportInfo" class="...">
+ * <result name="showReportResult" type="redirectAction">
+ * <param name="actionName">generateReport</param>
+ * <param name="namespace">/genReport</param>
+ * <param name="reportType">pie</param>
+ * <param name="width">100</param>
+ * <param name="height">100</param>
+ * </result>
+ * </action>
+ * </package>
+ *
+ *
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * @see ActionMapper
+ */
+public class PortletActionRedirectResult extends PortletResult implements ReflectionExceptionHandler {
+
+ private static final long serialVersionUID = -7627388936683562557L;
+
+ private static final Logger LOG = LoggerFactory.getLogger(PortletActionRedirectResult.class);
+
+ /** The default parameter */
+ public static final String DEFAULT_PARAM = "actionName";
+
+ protected String actionName;
+
+ protected String namespace;
+
+ protected String method;
+
+ private Map<String, String> requestParameters = new LinkedHashMap<String, String>();
+
+ private ActionMapper actionMapper;
+
+ public PortletActionRedirectResult() {
+ super();
+ }
+
+ public PortletActionRedirectResult(String actionName) {
+ this(null, actionName, null);
+ }
+
+ public PortletActionRedirectResult(String actionName, String method) {
+ this(null, actionName, method);
+ }
+
+ public PortletActionRedirectResult(String namespace, String actionName, String method) {
+ super(null);
+ this.namespace = namespace;
+ this.actionName = actionName;
+ this.method = method;
+ }
+
+ protected List<String> prohibitedResultParam = Arrays.asList(new String[] { DEFAULT_PARAM, "namespace", "method",
+ "encode", "parse", "location", "prependServletContext" });
+
+ @Inject
+ public void setActionMapper(ActionMapper actionMapper) {
+ this.actionMapper = actionMapper;
+ }
+
+ /**
+ * @see com.opensymphony.xwork2.Result#execute(com.opensymphony.xwork2.ActionInvocation)
+ */
+ public void execute(ActionInvocation invocation) throws Exception {
+ actionName = conditionalParse(actionName, invocation);
+ if (portletMode != null) {
+ Map<PortletMode, String> namespaceMap = (Map<PortletMode, String>) invocation.getInvocationContext().get(
+ PortletActionConstants.MODE_NAMESPACE_MAP);
+ namespace = namespaceMap.get(portletMode);
+ }
+ if (namespace == null) {
+ namespace = invocation.getProxy().getNamespace();
+ } else {
+ namespace = conditionalParse(namespace, invocation);
+ }
+ if (method == null) {
+ method = "";
+ } else {
+ method = conditionalParse(method, invocation);
+ }
+
+ String resultCode = invocation.getResultCode();
+ if (resultCode != null) {
+ ResultConfig resultConfig = invocation.getProxy().getConfig().getResults().get(resultCode);
+ Map resultConfigParams = resultConfig.getParams();
+ for (Iterator i = resultConfigParams.entrySet().iterator(); i.hasNext();) {
+ Map.Entry e = (Map.Entry) i.next();
+ if (!prohibitedResultParam.contains(e.getKey())) {
+ requestParameters.put(e.getKey().toString(), e.getValue() == null ? "" : conditionalParse(e
+ .getValue().toString(), invocation));
+ }
+ }
+ }
+
+ StringBuilder tmpLocation = new StringBuilder(actionMapper.getUriFromActionMapping(new ActionMapping(actionName,
+ namespace, method, null)));
+ UrlHelper.buildParametersString(requestParameters, tmpLocation, "&");
+
+ setLocation(tmpLocation.toString());
+
+ super.execute(invocation);
+ }
+
+ /**
+ * Sets the action name
+ *
+ * @param actionName
+ * The name
+ */
+ public void setActionName(String actionName) {
+ this.actionName = actionName;
+ }
+
+ /**
+ * Sets the namespace
+ *
+ * @param namespace
+ * The namespace
+ */
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ /**
+ * Sets the method
+ *
+ * @param method
+ * The method
+ */
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ /**
+ * Adds a request parameter to be added to the redirect url
+ *
+ * @param key
+ * The parameter name
+ * @param value
+ * The parameter value
+ */
+ public PortletActionRedirectResult addParameter(String key, Object value) {
+ requestParameters.put(key, String.valueOf(value));
+ return this;
+ }
+
+ public void handle(ReflectionException ex) {
+ // Only log as debug as they are probably parameters to be appended to the url
+ if (LOG.isDebugEnabled()) LOG.debug(ex.getMessage(), ex);
+ }
+}
Added: struts/archive/plugins/src/main/java/org/apache/struts2/portlet/result/PortletResult.java
URL: http://svn.apache.org/viewvc/struts/archive/plugins/src/main/java/org/apache/struts2/portlet/result/PortletResult.java?rev=1139061&view=auto
==============================================================================
--- struts/archive/plugins/src/main/java/org/apache/struts2/portlet/result/PortletResult.java (added)
+++ struts/archive/plugins/src/main/java/org/apache/struts2/portlet/result/PortletResult.java Thu Jun 23 20:18:43 2011
@@ -0,0 +1,243 @@
+/*
+ * $Id: PortletResult.java 1076544 2011-03-03 07:19:37Z lukaszlenart $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.portlet.result;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+import org.apache.commons.lang.StringUtils;
+import org.apache.struts2.ServletActionContext;
+import org.apache.struts2.dispatcher.StrutsResultSupport;
+import org.apache.struts2.portlet.PortletActionConstants;
+import org.apache.struts2.portlet.context.PortletActionContext;
+
+import javax.portlet.ActionResponse;
+import javax.portlet.PortletContext;
+import javax.portlet.PortletException;
+import javax.portlet.PortletMode;
+import javax.portlet.PortletRequestDispatcher;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * Result type that includes a JSP to render.
+ *
+ */
+public class PortletResult extends StrutsResultSupport implements PortletActionConstants {
+
+ private static final long serialVersionUID = 434251393926178567L;
+
+ private boolean useDispatcherServlet;
+
+ private String dispatcherServletName = DEFAULT_DISPATCHER_SERVLET_NAME;
+
+ /**
+ * Logger instance.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(PortletResult.class);
+
+ private String contentType = "text/html";
+
+ private String title;
+
+ protected PortletMode portletMode;
+
+ public PortletResult() {
+ super();
+ }
+
+ public PortletResult(String location) {
+ super(location);
+ }
+
+ /**
+ * Execute the result. Obtains the
+ * {@link javax.portlet.PortletRequestDispatcher}from the
+ * {@link PortletActionContext}and includes the JSP.
+ *
+ * @see com.opensymphony.xwork2.Result#execute(com.opensymphony.xwork2.ActionInvocation)
+ */
+ public void doExecute(String finalLocation, ActionInvocation actionInvocation) throws Exception {
+
+ if (PortletActionContext.isRender()) {
+ executeRenderResult(finalLocation);
+ } else if (PortletActionContext.isEvent()) {
+ executeActionResult(finalLocation, actionInvocation);
+ } else {
+ executeRegularServletResult(finalLocation, actionInvocation);
+ }
+ }
+
+ /**
+ * Executes the regular servlet result.
+ *
+ * @param finalLocation
+ * @param actionInvocation
+ */
+ private void executeRegularServletResult(String finalLocation, ActionInvocation actionInvocation)
+ throws ServletException, IOException {
+ ServletContext ctx = ServletActionContext.getServletContext();
+ HttpServletRequest req = ServletActionContext.getRequest();
+ HttpServletResponse res = ServletActionContext.getResponse();
+ try {
+ ctx.getRequestDispatcher(finalLocation).include(req, res);
+ } catch (ServletException e) {
+ LOG.error("ServletException including " + finalLocation, e);
+ throw e;
+ } catch (IOException e) {
+ LOG.error("IOException while including result '" + finalLocation + "'", e);
+ throw e;
+ }
+ }
+
+ /**
+ * Executes the action result.
+ *
+ * @param finalLocation
+ * @param invocation
+ */
+ protected void executeActionResult(String finalLocation, ActionInvocation invocation) throws Exception {
+ if (LOG.isDebugEnabled()) LOG.debug("Executing result in Event phase");
+ ActionResponse res = PortletActionContext.getActionResponse();
+ Map sessionMap = invocation.getInvocationContext().getSession();
+ if (LOG.isDebugEnabled()) LOG.debug("Setting event render parameter: " + finalLocation);
+ if (finalLocation.indexOf('?') != -1) {
+ convertQueryParamsToRenderParams(res, finalLocation.substring(finalLocation.indexOf('?') + 1));
+ finalLocation = finalLocation.substring(0, finalLocation.indexOf('?'));
+ }
+ if (finalLocation.endsWith(".action")) {
+ // View is rendered with a view action...luckily...
+ finalLocation = finalLocation.substring(0, finalLocation.lastIndexOf("."));
+ res.setRenderParameter(ACTION_PARAM, finalLocation);
+ } else {
+ // View is rendered outside an action...uh oh...
+ String namespace = invocation.getProxy().getNamespace();
+ if ( namespace != null && namespace.length() > 0 && !namespace.endsWith("/")) {
+ namespace += "/";
+
+ }
+ res.setRenderParameter(ACTION_PARAM, namespace + "renderDirect");
+ sessionMap.put(RENDER_DIRECT_LOCATION, finalLocation);
+ }
+ if(portletMode != null) {
+ res.setPortletMode(portletMode);
+ res.setRenderParameter(PortletActionConstants.MODE_PARAM, portletMode.toString());
+ }
+ else {
+ res.setRenderParameter(PortletActionConstants.MODE_PARAM, PortletActionContext.getRequest().getPortletMode()
+ .toString());
+ }
+ }
+
+ /**
+ * Converts the query params to render params.
+ *
+ * @param response
+ * @param queryParams
+ */
+ protected static void convertQueryParamsToRenderParams(ActionResponse response, String queryParams) {
+ StringTokenizer tok = new StringTokenizer(queryParams, "&");
+ while (tok.hasMoreTokens()) {
+ String token = tok.nextToken();
+ String key = token.substring(0, token.indexOf('='));
+ String value = token.substring(token.indexOf('=') + 1);
+ response.setRenderParameter(key, value);
+ }
+ }
+
+ /**
+ * Executes the render result.
+ *
+ * @param finalLocation
+ * @throws PortletException
+ * @throws IOException
+ */
+ protected void executeRenderResult(final String finalLocation) throws PortletException, IOException {
+ if (LOG.isDebugEnabled()) LOG.debug("Executing result in Render phase");
+ PortletContext ctx = PortletActionContext.getPortletContext();
+ RenderRequest req = PortletActionContext.getRenderRequest();
+ RenderResponse res = PortletActionContext.getRenderResponse();
+ res.setContentType(contentType);
+ if (StringUtils.isNotEmpty(title)) {
+ res.setTitle(title);
+ }
+ if (LOG.isDebugEnabled()) 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.
+ *
+ * @param contentType
+ * The content type to set.
+ */
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ /**
+ * Sets the title.
+ *
+ * @param title
+ * The title to set.
+ */
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public void setPortletMode(String portletMode) {
+ if(portletMode != null) {
+ this.portletMode = new PortletMode(portletMode);
+ }
+ }
+
+ @Inject("struts.portlet.useDispatcherServlet")
+ public void setUseDispatcherServlet(String useDispatcherServlet) {
+ this.useDispatcherServlet = "true".equalsIgnoreCase(useDispatcherServlet);
+ }
+
+ @Inject("struts.portlet.dispatcherServletName")
+ public void setDispatcherServletName(String dispatcherServletName) {
+ this.dispatcherServletName = dispatcherServletName;
+ }
+}
Added: struts/archive/plugins/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java
URL: http://svn.apache.org/viewvc/struts/archive/plugins/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java?rev=1139061&view=auto
==============================================================================
--- struts/archive/plugins/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java (added)
+++ struts/archive/plugins/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java Thu Jun 23 20:18:43 2011
@@ -0,0 +1,291 @@
+/*
+ * $Id: PortletVelocityResult.java 1074051 2011-02-24 06:53:20Z lukaszlenart $
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.struts2.portlet.result;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+import org.apache.struts2.ServletActionContext;
+import org.apache.struts2.StrutsConstants;
+import org.apache.struts2.dispatcher.StrutsResultSupport;
+import org.apache.struts2.portlet.PortletActionConstants;
+import org.apache.struts2.portlet.context.PortletActionContext;
+import org.apache.struts2.views.JspSupportServlet;
+import org.apache.struts2.views.velocity.VelocityManager;
+import org.apache.velocity.Template;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.context.Context;
+
+import javax.portlet.ActionResponse;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspFactory;
+import javax.servlet.jsp.PageContext;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+/**
+ * <!-- START SNIPPET: description -->
+ *
+ * Using the Servlet container's {@link JspFactory}, this result mocks a JSP
+ * execution environment and then displays a Velocity template that will be
+ * streamed directly to the servlet output.
+ *
+ * <!-- END SNIPPET: description --> <p/><b>This result type takes the
+ * following parameters: </b>
+ *
+ * <!-- START SNIPPET: params -->
+ *
+ * <ul>
+ *
+ * <li><b>location (default) </b>- the location of the template to process.
+ * </li>
+ *
+ * <li><b>parse </b>- true by default. If set to false, the location param
+ * will not be parsed for Ognl expressions.</li>
+ *
+ * </ul>
+ * <p>
+ * This result follows the same rules from {@link StrutsResultSupport}.
+ * </p>
+ *
+ * <!-- END SNIPPET: params -->
+ *
+ * <b>Example: </b>
+ *
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * <result name="success" type="velocity">
+ * <param name="location">foo.vm</param>
+ * </result>
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ */
+public class PortletVelocityResult extends StrutsResultSupport {
+
+ private static final long serialVersionUID = -8241086555872212274L;
+
+ private static final Logger LOG = LoggerFactory.getLogger(PortletVelocityResult.class);
+
+ private String defaultEncoding;
+ private VelocityManager velocityManager;
+ private JspFactory jspFactory = JspFactory.getDefaultFactory();
+
+ public PortletVelocityResult() {
+ super();
+ }
+
+ public PortletVelocityResult(String location) {
+ super(location);
+ }
+
+ @Inject
+ public void setVelocityManager(VelocityManager mgr) {
+ this.velocityManager = mgr;
+ }
+
+ @Inject(StrutsConstants.STRUTS_I18N_ENCODING)
+ public void setDefaultEncoding(String encoding) {
+ this.defaultEncoding = encoding;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.struts2.dispatcher.StrutsResultSupport#doExecute(java.lang.String, com.opensymphony.xwork2.ActionInvocation)
+ */
+ public void doExecute(String location, ActionInvocation invocation)
+ throws Exception {
+ if (PortletActionContext.isEvent()) {
+ executeActionResult(location, invocation);
+ } else if (PortletActionContext.isRender()) {
+ executeRenderResult(location, invocation);
+ }
+ }
+
+ /**
+ * Executes the result
+ *
+ * @param location The location string
+ * @param invocation The action invocation
+ */
+ private void executeActionResult(String location,
+ ActionInvocation invocation) {
+ ActionResponse res = PortletActionContext.getActionResponse();
+ // View is rendered outside an action...uh oh...
+ String namespace = invocation.getProxy().getNamespace();
+ if ( namespace != null && namespace.length() > 0 && !namespace.endsWith("/")) {
+ namespace += "/";
+
+ }
+ res.setRenderParameter(PortletActionConstants.ACTION_PARAM, namespace + "freemarkerDirect");
+ res.setRenderParameter("location", location);
+ res.setRenderParameter(PortletActionConstants.MODE_PARAM, PortletActionContext
+ .getRequest().getPortletMode().toString());
+
+ }
+
+ /**
+ * Creates a Velocity context from the action, loads a Velocity template and
+ * executes the template. Output is written to the servlet output stream.
+ *
+ * @param finalLocation the location of the Velocity template
+ * @param invocation an encapsulation of the action execution state.
+ * @throws Exception if an error occurs when creating the Velocity context,
+ * loading or executing the template or writing output to the
+ * servlet response stream.
+ */
+ public void executeRenderResult(String finalLocation,
+ ActionInvocation invocation) throws Exception {
+ ValueStack stack = ActionContext.getContext().getValueStack();
+
+ HttpServletRequest request = ServletActionContext.getRequest();
+ HttpServletResponse response = ServletActionContext.getResponse();
+ ServletContext servletContext = ServletActionContext
+ .getServletContext();
+ Servlet servlet = JspSupportServlet.jspSupportServlet;
+
+ velocityManager.init(servletContext);
+
+ boolean usedJspFactory = false;
+ PageContext pageContext = (PageContext) ActionContext.getContext().get(
+ ServletActionContext.PAGE_CONTEXT);
+
+ if (pageContext == null && servlet != null) {
+ pageContext = jspFactory.getPageContext(servlet, request, response,
+ null, true, 8192, true);
+ ActionContext.getContext().put(ServletActionContext.PAGE_CONTEXT,
+ pageContext);
+ usedJspFactory = true;
+ }
+
+ try {
+ String encoding = getEncoding(finalLocation);
+ String contentType = getContentType(finalLocation);
+
+ if (encoding != null) {
+ contentType = contentType + ";charset=" + encoding;
+ }
+ response.setContentType(contentType);
+ Template t = getTemplate(stack,
+ velocityManager.getVelocityEngine(), invocation,
+ finalLocation, encoding);
+
+ Context context = createContext(velocityManager, stack, request,
+ response, finalLocation);
+ Writer writer = new OutputStreamWriter(response.getOutputStream(),
+ encoding);
+
+ t.merge(context, writer);
+
+ // always flush the writer (we used to only flush it if this was a
+ // jspWriter, but someone asked
+ // to do it all the time (WW-829). Since Velocity support is being
+ // deprecated, we'll oblige :)
+ writer.flush();
+ } catch (Exception e) {
+ LOG.error("Unable to render Velocity Template, '" + finalLocation
+ + "'", e);
+ throw e;
+ } finally {
+ if (usedJspFactory) {
+ jspFactory.releasePageContext(pageContext);
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * Retrieve the content type for this template. <p/>People can override
+ * this method if they want to provide specific content types for specific
+ * templates (eg text/xml).
+ *
+ * @return The content type associated with this template (default
+ * "text/html")
+ */
+ protected String getContentType(String templateLocation) {
+ return "text/html";
+ }
+
+ /**
+ * Retrieve the encoding for this template. <p/>People can override this
+ * method if they want to provide specific encodings for specific templates.
+ *
+ * @return The encoding associated with this template (defaults to the value
+ * of 'struts.i18n.encoding' property)
+ */
+ protected String getEncoding(String templateLocation) {
+ String encoding = defaultEncoding;
+ if (encoding == null) {
+ encoding = System.getProperty("file.encoding");
+ }
+ if (encoding == null) {
+ encoding = "UTF-8";
+ }
+ return encoding;
+ }
+
+ /**
+ * Given a value stack, a Velocity engine, and an action invocation, this
+ * method returns the appropriate Velocity template to render.
+ *
+ * @param stack the value stack to resolve the location again (when parse
+ * equals true)
+ * @param velocity the velocity engine to process the request against
+ * @param invocation an encapsulation of the action execution state.
+ * @param location the location of the template
+ * @param encoding the charset encoding of the template
+ * @return the template to render
+ * @throws Exception when the requested template could not be found
+ */
+ protected Template getTemplate(ValueStack stack,
+ VelocityEngine velocity, ActionInvocation invocation,
+ String location, String encoding) throws Exception {
+ if (!location.startsWith("/")) {
+ location = invocation.getProxy().getNamespace() + "/" + location;
+ }
+
+ Template template = velocity.getTemplate(location, encoding);
+
+ return template;
+ }
+
+ /**
+ * Creates the VelocityContext that we'll use to render this page.
+ *
+ * @param velocityManager a reference to the velocityManager to use
+ * @param stack the value stack to resolve the location against (when parse
+ * equals true)
+ * @param location the name of the template that is being used
+ * @return the a minted Velocity context.
+ */
+ protected Context createContext(VelocityManager velocityManager,
+ ValueStack stack, HttpServletRequest request,
+ HttpServletResponse response, String location) {
+ return velocityManager.createContext(stack, request, response);
+ }
+}