WW-1645 Refactored portlet support into a plugin.

git-svn-id: https://svn.apache.org/repos/asf/struts/struts2/trunk@557544 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nils-Helge Garli
2007-07-19 10:03:06 +00:00
parent bfdd49d7de
commit 48d2edd312
45 changed files with 677 additions and 238 deletions
+1
View File
@@ -32,6 +32,7 @@
<module>struts1</module>
<module>tiles</module>
<module>dojo</module>
<module>portlet</module>
</modules>
<dependencies>
+107
View File
@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.1.0-SNAPSHOT</version>
</parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-portlet-plugin</artifactId>
<packaging>jar</packaging>
<name>Struts 2 Portlet Plugin</name>
<scm>
<connection>scm:svn:http://svn.apache.org/repos/asf/struts/struts2/trunk/plugins/portlet/</connection>
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/struts/struts2/trunk/plugins/portlet/</developerConnection>
<url>http://svn.apache.org/viewcvs.cgi/struts/struts2/trunk/plugins/portlet/</url>
</scm>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<!-- Velocity -->
<dependency>
<groupId>velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.4</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>velocity-tools</groupId>
<artifactId>velocity-tools</artifactId>
<version>1.1</version>
<optional>true</optional>
</dependency>
<!-- Portlet -->
<dependency>
<groupId>portlet-api</groupId>
<artifactId>portlet-api</artifactId>
<version>1.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mockobjects</groupId>
<artifactId>mockobjects-jdk1.3-j2ee1.3</artifactId>
<version>0.09</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jmock</groupId>
<artifactId>jmock</artifactId>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jmock</groupId>
<artifactId>jmock-cglib</artifactId>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mockobjects</groupId>
<artifactId>mockobjects-core</artifactId>
<version>0.09</version>
<scope>test</scope>
</dependency>
<!-- Mocks for unit testing (by Spring) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-mock</artifactId>
<version>1.2.8</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>1.2.8</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,104 @@
package org.apache.struts2.components;
import java.io.IOException;
import java.io.Writer;
import org.apache.struts2.StrutsException;
import org.apache.struts2.components.URL;
import org.apache.struts2.components.UrlRenderer;
import org.apache.struts2.portlet.util.PortletUrlHelper;
import com.opensymphony.xwork2.util.TextUtils;
/**
* Implementation of the {@link URLRenderer} interface that renders URLs for portlet environments.
*
* @see URLRenderer
*
*/
public class PortletUrlRenderer implements UrlRenderer {
/**
* {@inheritDoc}
*/
public void renderUrl(Writer writer, URL urlComponent) {
String scheme = urlComponent.req.getScheme();
if (urlComponent.scheme != null) {
scheme = urlComponent.scheme;
}
String result;
if (urlComponent.value == null && urlComponent.action != null) {
result = PortletUrlHelper.buildUrl(urlComponent.action, urlComponent.namespace, urlComponent.parameters, urlComponent.portletUrlType, urlComponent.portletMode, urlComponent.windowState);
} else {
result = PortletUrlHelper.buildResourceUrl(urlComponent.value, urlComponent.parameters);
}
if ( urlComponent.anchor != null && urlComponent.anchor.length() > 0 ) {
result += '#' + urlComponent.anchor;
}
String var = urlComponent.getVar();
if (var != null) {
urlComponent.putInContext(result);
// add to the request and page scopes as well
urlComponent.req.setAttribute(var, result);
} else {
try {
writer.write(result);
} catch (IOException e) {
throw new StrutsException("IOError: " + e.getMessage(), e);
}
}
}
/**
* {@inheritDoc}
*/
public void renderFormUrl(Form formComponent) {
String action = null;
if (formComponent.action != null) {
// if it isn't specified, we'll make somethig up
action = formComponent.findString(formComponent.action);
}
String type = "action";
if (TextUtils.stringSet(formComponent.method)) {
if ("GET".equalsIgnoreCase(formComponent.method.trim())) {
type = "render";
}
}
if (action != null) {
String result = PortletUrlHelper.buildUrl(action, formComponent.namespace,
formComponent.getParameters(), type, formComponent.portletMode, formComponent.windowState);
formComponent.addParameter("action", result);
// namespace: cut out anything between the start and the last /
int slash = result.lastIndexOf('/');
if (slash != -1) {
formComponent.addParameter("namespace", result.substring(0, slash));
} else {
formComponent.addParameter("namespace", "");
}
// name/id: cut out anything between / and . should be the id and
// name
String id = formComponent.getId();
if (id == null) {
slash = action.lastIndexOf('/');
int dot = action.indexOf('.', slash);
if (dot != -1) {
id = action.substring(slash + 1, dot);
} else {
id = action.substring(slash + 1);
}
formComponent.addParameter("id", formComponent.escape(id));
}
}
}
}
@@ -0,0 +1,106 @@
/*
* $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;
/**
* Interface defining some constants used in the Struts portlet implementation
*
*/
public interface PortletActionConstants {
/**
* Default action name to use when no default action has been configured in the portlet
* init parameters.
*/
String DEFAULT_ACTION_NAME = "default";
/**
* Action name parameter name
*/
String ACTION_PARAM = "struts.portlet.action";
/**
* Key for parameter holding the last executed portlet mode.
*/
String MODE_PARAM = "struts.portlet.mode";
/**
* Key used for looking up and storing the portlet phase
*/
String PHASE = "struts.portlet.phase";
/**
* Constant used for the render phase (
* {@link javax.portlet.Portlet#render(javax.portlet.RenderRequest, javax.portlet.RenderResponse)})
*/
Integer RENDER_PHASE = new Integer(1);
/**
* Constant used for the event phase (
* {@link javax.portlet.Portlet#processAction(javax.portlet.ActionRequest, javax.portlet.ActionResponse)})
*/
Integer EVENT_PHASE = new Integer(2);
/**
* Key used for looking up and storing the
* {@link javax.portlet.PortletRequest}
*/
String REQUEST = "struts.portlet.request";
/**
* Key used for looking up and storing the
* {@link javax.portlet.PortletResponse}
*/
String RESPONSE = "struts.portlet.response";
/**
* Key used for looking up and storing the action that was invoked in the event phase.
*/
String EVENT_ACTION = "struts.portlet.eventAction";
/**
* Key used for looking up and storing the
* {@link javax.portlet.PortletConfig}
*/
String PORTLET_CONFIG = "struts.portlet.config";
/**
* Name of the action used as error handler
*/
String ERROR_ACTION = "errorHandler";
/**
* Key for the portlet namespace stored in the
* {@link org.apache.struts2.portlet.context.PortletActionContext}.
*/
String PORTLET_NAMESPACE = "struts.portlet.portletNamespace";
/**
* Key for the mode-to-namespace map stored in the
* {@link org.apache.struts2.portlet.context.PortletActionContext}.
*/
String MODE_NAMESPACE_MAP = "struts.portlet.modeNamespaceMap";
/**
* Key for the default action name for the portlet, stored in the
* {@link org.apache.struts2.portlet.context.PortletActionContext}.
*/
String DEFAULT_ACTION_FOR_MODE = "struts.portlet.defaultActionForMode";
}
@@ -0,0 +1,206 @@
/*
* $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;
import java.io.Serializable;
import java.util.AbstractMap;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.portlet.PortletContext;
/**
* Portlet specific {@link java.util.Map} implementation representing the
* {@link javax.portlet.PortletContext} of a Portlet.
*
*/
public class PortletApplicationMap extends AbstractMap implements Serializable {
private static final long serialVersionUID = 2296107511063504414L;
private PortletContext context;
private Set<Object> entries;
/**
* Creates a new map object given the {@link PortletContext}.
*
* @param ctx The portlet context.
*/
public PortletApplicationMap(PortletContext ctx) {
this.context = ctx;
}
/**
* Removes all entries from the Map and removes all attributes from the
* portlet context.
*/
public void clear() {
entries = null;
Enumeration e = context.getAttributeNames();
while (e.hasMoreElements()) {
context.removeAttribute(e.nextElement().toString());
}
}
/**
* Creates a Set of all portlet context attributes as well as context init
* parameters.
*
* @return a Set of all portlet context attributes as well as context init
* parameters.
*/
public Set entrySet() {
if (entries == null) {
entries = new HashSet<Object>();
// Add portlet context attributes
Enumeration enumeration = context.getAttributeNames();
while (enumeration.hasMoreElements()) {
final String key = enumeration.nextElement().toString();
final Object value = context.getAttribute(key);
entries.add(new Map.Entry() {
public boolean equals(Object obj) {
Map.Entry entry = (Map.Entry) obj;
return ((key == null) ? (entry.getKey() == null) : key
.equals(entry.getKey()))
&& ((value == null) ? (entry.getValue() == null)
: value.equals(entry.getValue()));
}
public int hashCode() {
return ((key == null) ? 0 : key.hashCode())
^ ((value == null) ? 0 : value.hashCode());
}
public Object getKey() {
return key;
}
public Object getValue() {
return value;
}
public Object setValue(Object obj) {
context.setAttribute(key.toString(), obj);
return value;
}
});
}
// Add portlet context init params
enumeration = context.getInitParameterNames();
while (enumeration.hasMoreElements()) {
final String key = enumeration.nextElement().toString();
final Object value = context.getInitParameter(key);
entries.add(new Map.Entry() {
public boolean equals(Object obj) {
Map.Entry entry = (Map.Entry) obj;
return ((key == null) ? (entry.getKey() == null) : key
.equals(entry.getKey()))
&& ((value == null) ? (entry.getValue() == null)
: value.equals(entry.getValue()));
}
public int hashCode() {
return ((key == null) ? 0 : key.hashCode())
^ ((value == null) ? 0 : value.hashCode());
}
public Object getKey() {
return key;
}
public Object getValue() {
return value;
}
public Object setValue(Object obj) {
context.setAttribute(key.toString(), obj);
return value;
}
});
}
}
return entries;
}
/**
* Returns the portlet context attribute or init parameter based on the
* given key. If the entry is not found, <tt>null</tt> is returned.
*
* @param key
* the entry key.
* @return the portlet context attribute or init parameter or <tt>null</tt>
* if the entry is not found.
*/
public Object get(Object key) {
// Try context attributes first, then init params
// This gives the proper shadowing effects
String keyString = key.toString();
Object value = context.getAttribute(keyString);
return (value == null) ? context.getInitParameter(keyString) : value;
}
/**
* Sets a portlet context attribute given a attribute name and value.
*
* @param key
* the name of the attribute.
* @param value
* the value to set.
* @return the attribute that was just set.
*/
public Object put(Object key, Object value) {
entries = null;
context.setAttribute(key.toString(), value);
return get(key);
}
/**
* Removes the specified portlet context attribute.
*
* @param key
* the attribute to remove.
* @return the entry that was just removed.
*/
public Object remove(Object key) {
entries = null;
Object value = get(key);
context.removeAttribute(key.toString());
return value;
}
}
@@ -0,0 +1,167 @@
/*
* $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;
import java.util.AbstractMap;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.portlet.PortletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A simple implementation of the {@link java.util.Map} interface to handle a collection of request attributes.
*
*/
public class PortletRequestMap extends AbstractMap {
private static final Log LOG = LogFactory.getLog(PortletRequestMap.class);
private Set<Object> entries = null;
private PortletRequest request = null;
/**
* Saves the request to use as the backing for getting and setting values
*
* @param request the portlet request.
*/
public PortletRequestMap(PortletRequest request) {
this.request = request;
if(LOG.isDebugEnabled()) {
LOG.debug("Dumping request parameters: ");
Iterator params = request.getParameterMap().keySet().iterator();
while(params.hasNext()) {
String key = (String)params.next();
String val = request.getParameter(key);
LOG.debug(key + " = " + val);
}
}
}
/**
* Removes all attributes from the request as well as clears entries in this
* map.
*/
public void clear() {
entries = null;
Enumeration keys = request.getAttributeNames();
while (keys.hasMoreElements()) {
String key = (String) keys.nextElement();
request.removeAttribute(key);
}
}
/**
* Returns a Set of attributes from the portlet request.
*
* @return a Set of attributes from the portlet request.
*/
public Set entrySet() {
if (entries == null) {
entries = new HashSet<Object>();
Enumeration enumeration = request.getAttributeNames();
while (enumeration.hasMoreElements()) {
final String key = enumeration.nextElement().toString();
final Object value = request.getAttribute(key);
entries.add(new Entry() {
public boolean equals(Object obj) {
Entry entry = (Entry) obj;
return ((key == null) ? (entry.getKey() == null) : key
.equals(entry.getKey()))
&& ((value == null) ? (entry.getValue() == null)
: value.equals(entry.getValue()));
}
public int hashCode() {
return ((key == null) ? 0 : key.hashCode())
^ ((value == null) ? 0 : value.hashCode());
}
public Object getKey() {
return key;
}
public Object getValue() {
return value;
}
public Object setValue(Object obj) {
request.setAttribute(key, obj);
return value;
}
});
}
}
return entries;
}
/**
* Returns the request attribute associated with the given key or
* <tt>null</tt> if it doesn't exist.
*
* @param key the name of the request attribute.
* @return the request attribute or <tt>null</tt> if it doesn't exist.
*/
public Object get(Object key) {
return request.getAttribute(key.toString());
}
/**
* Saves an attribute in the request.
*
* @param key the name of the request attribute.
* @param value the value to set.
* @return the object that was just set.
*/
public Object put(Object key, Object value) {
entries = null;
request.setAttribute(key.toString(), value);
return get(key);
}
/**
* Removes the specified request attribute.
*
* @param key the name of the attribute to remove.
* @return the value that was removed or <tt>null</tt> if the value was
* not found (and hence, not removed).
*/
public Object remove(Object key) {
entries = null;
Object value = get(key);
request.removeAttribute(key.toString());
return value;
}
}
@@ -0,0 +1,171 @@
/*
* $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;
import java.util.AbstractMap;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A simple implementation of the {@link java.util.Map} interface to handle a collection of portlet session
* attributes. The {@link #entrySet()} method enumerates over all session attributes and creates a Set of entries.
* Note, this will occur lazily - only when the entry set is asked for.
*
*/
public class PortletSessionMap extends AbstractMap {
private static final Log LOG = LogFactory.getLog(PortletSessionMap.class);
private PortletSession session = null;
private Set<Object> entries = null;
/**
* Creates a new session map given a portlet request.
*
* @param request the portlet request object.
*/
public PortletSessionMap(PortletRequest request) {
this.session = request.getPortletSession();
if(LOG.isDebugEnabled()) {
LOG.debug("Dumping session info: ");
Enumeration enumeration = session.getAttributeNames();
while(enumeration.hasMoreElements()) {
String key = (String)enumeration.nextElement();
Object val = session.getAttribute(key);
LOG.debug(key + " = " + val);
}
}
}
/**
* @see java.util.Map#entrySet()
*/
public Set entrySet() {
synchronized (session) {
if (entries == null) {
entries = new HashSet<Object>();
Enumeration enumeration = session.getAttributeNames();
while (enumeration.hasMoreElements()) {
final String key = enumeration.nextElement().toString();
final Object value = session.getAttribute(key);
entries.add(new Map.Entry() {
public boolean equals(Object obj) {
Map.Entry entry = (Map.Entry) obj;
return ((key == null) ? (entry.getKey() == null)
: key.equals(entry.getKey()))
&& ((value == null) ? (entry.getValue() == null)
: value.equals(entry.getValue()));
}
public int hashCode() {
return ((key == null) ? 0 : key.hashCode())
^ ((value == null) ? 0 : value.hashCode());
}
public Object getKey() {
return key;
}
public Object getValue() {
return value;
}
public Object setValue(Object obj) {
session.setAttribute(key, obj);
return value;
}
});
}
}
}
return entries;
}
/**
* Returns the session attribute associated with the given key or
* <tt>null</tt> if it doesn't exist.
*
* @param key the name of the session attribute.
* @return the session attribute or <tt>null</tt> if it doesn't exist.
*/
public Object get(Object key) {
synchronized (session) {
return session.getAttribute(key.toString());
}
}
/**
* Saves an attribute in the session.
*
* @param key the name of the session attribute.
* @param value the value to set.
* @return the object that was just set.
*/
public Object put(Object key, Object value) {
synchronized (session) {
entries = null;
session.setAttribute(key.toString(), value);
return get(key);
}
}
/**
* @see java.util.Map#clear()
*/
public void clear() {
synchronized (session) {
entries = null;
session.invalidate();
}
}
/**
* Removes the specified session attribute.
*
* @param key the name of the attribute to remove.
* @return the value that was removed or <tt>null</tt> if the value was
* not found (and hence, not removed).
*/
public Object remove(Object key) {
synchronized (session) {
entries = null;
Object value = get(key);
session.removeAttribute(key.toString());
return value;
}
}
}
@@ -0,0 +1,197 @@
/*
* $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.context;
import java.util.Map;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletConfig;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.portlet.PortletActionConstants;
import com.opensymphony.xwork2.ActionContext;
/**
* PortletActionContext. ActionContext thread local for the portlet environment.
*
* @version $Revision$ $Date$
*/
public class PortletActionContext implements PortletActionConstants {
/**
* Get the PortletConfig of the portlet that is executing.
*
* @return The PortletConfig of the executing portlet.
*/
public static PortletConfig getPortletConfig() {
return (PortletConfig) getContext().get(PORTLET_CONFIG);
}
/**
* Get the RenderRequest. Can only be invoked in the render phase.
*
* @return The current RenderRequest.
* @throws IllegalStateException If the method is invoked in the wrong phase.
*/
public static RenderRequest getRenderRequest() {
if (!isRender()) {
throw new IllegalStateException(
"RenderRequest cannot be obtained in event phase");
}
return (RenderRequest) getContext().get(REQUEST);
}
/**
* Get the RenderResponse. Can only be invoked in the render phase.
*
* @return The current RenderResponse.
* @throws IllegalStateException If the method is invoked in the wrong phase.
*/
public static RenderResponse getRenderResponse() {
if (!isRender()) {
throw new IllegalStateException(
"RenderResponse cannot be obtained in event phase");
}
return (RenderResponse) getContext().get(RESPONSE);
}
/**
* Get the ActionRequest. Can only be invoked in the event phase.
*
* @return The current ActionRequest.
* @throws IllegalStateException If the method is invoked in the wrong phase.
*/
public static ActionRequest getActionRequest() {
if (!isEvent()) {
throw new IllegalStateException(
"ActionRequest cannot be obtained in render phase");
}
return (ActionRequest) getContext().get(REQUEST);
}
/**
* Get the ActionRequest. Can only be invoked in the event phase.
*
* @return The current ActionRequest.
* @throws IllegalStateException If the method is invoked in the wrong phase.
*/
public static ActionResponse getActionResponse() {
if (!isEvent()) {
throw new IllegalStateException(
"ActionResponse cannot be obtained in render phase");
}
return (ActionResponse) getContext().get(RESPONSE);
}
/**
* Get the action namespace of the portlet. Used to organize actions for multiple portlets in
* the same portlet application.
*
* @return The portlet namespace as defined in <code>portlet.xml</code> and <code>struts.xml</code>
*/
public static String getPortletNamespace() {
return (String)getContext().get(PORTLET_NAMESPACE);
}
/**
* Get the current PortletRequest.
*
* @return The current PortletRequest.
*/
public static PortletRequest getRequest() {
return (PortletRequest) getContext().get(REQUEST);
}
/**
* Get the current PortletResponse
*
* @return The current PortletResponse.
*/
public static PortletResponse getResponse() {
return (PortletResponse) getContext().get(RESPONSE);
}
/**
* Get the phase that the portlet is executing in.
*
* @return {@link PortletActionConstants#RENDER_PHASE} in render phase, and
* {@link PortletActionConstants#EVENT_PHASE} in the event phase.
*/
public static Integer getPhase() {
return (Integer) getContext().get(PHASE);
}
/**
* @return <code>true</code> if the Portlet is executing in render phase.
*/
public static boolean isRender() {
return PortletActionConstants.RENDER_PHASE.equals(getPhase());
}
/**
* @return <code>true</code> if the Portlet is executing in the event phase.
*/
public static boolean isEvent() {
return PortletActionConstants.EVENT_PHASE.equals(getPhase());
}
/**
* @return The current ActionContext.
*/
private static ActionContext getContext() {
return ActionContext.getContext();
}
/**
* Check to see if the current request is a portlet request.
*
* @return <code>true</code> if the current request is a portlet request.
*/
public static boolean isPortletRequest() {
return getRequest() != null;
}
/**
* Get the default action mapping for the current mode.
*
* @return The default action mapping for the current portlet mode.
*/
public static ActionMapping getDefaultActionForMode() {
return (ActionMapping)getContext().get(DEFAULT_ACTION_FOR_MODE);
}
/**
* Get the namespace to mode mappings.
*
* @return The map of the namespaces for each mode.
*/
public static Map getModeNamespaceMap() {
return (Map)getContext().get(MODE_NAMESPACE_MAP);
}
}
@@ -0,0 +1,66 @@
/*
* $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.context;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.StrutsStatics;
import com.opensymphony.xwork2.ActionContext;
/**
* Since a portlet is not dispatched the same way as a servlet, the
* {@link org.apache.struts2.ServletActionContext} is not immediately available, as it
* depends on objects from the servlet API. However, the WW2 view implementations require access
* to the objects in the {@link org.apache.struts2.ServletActionContext}, and this servlet
* makes sure that these are available when the portlet actions are executing the render results.
*
*/
public class PreparatorServlet extends HttpServlet implements StrutsStatics {
private static final long serialVersionUID = 1853399729352984089L;
private final static Log LOG = LogFactory.getLog(PreparatorServlet.class);
/**
* Prepares the {@link org.apache.struts2.ServletActionContext} with the
* {@link ServletContext}, {@link HttpServletRequest} and {@link HttpServletResponse}.
*/
public void service(HttpServletRequest servletRequest,
HttpServletResponse servletResponse) throws ServletException,
IOException {
LOG.debug("Preparing servlet objects for dispatch");
ServletContext ctx = getServletContext();
ActionContext.getContext().put(SERVLET_CONTEXT, ctx);
ActionContext.getContext().put(HTTP_REQUEST, servletRequest);
ActionContext.getContext().put(HTTP_RESPONSE, servletResponse);
LOG.debug("Preparation complete");
}
}
@@ -0,0 +1,63 @@
/*
* $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.context;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* Some of the factory/managers (e.g. the ObjectFactory) need access to
* the {@link org.apache.struts2.ServletActionContext} object when initializing.
* This {@link javax.servlet.ServletContextListener} keeps a reference to the
* {@link javax.servlet.ServletContext} and exposes it through a <code>public static</code>
* method.
*
*/
public class ServletContextHolderListener implements ServletContextListener {
private static ServletContext context = null;
/**
* @return The current servlet context
*/
public static ServletContext getServletContext() {
return context;
}
/**
* Stores the reference to the {@link ServletContext}.
*
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent event) {
context = event.getServletContext();
}
/**
* @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent event) {
context = null;
}
}
@@ -0,0 +1,73 @@
/*
* $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.dispatcher;
import com.opensymphony.xwork2.Action;
import java.io.Serializable;
/**
* When a portlet is targetted for an <code>event</code>, the portlet will receive two
* portlet requests, one for the <code>event</code> phase, and then followed by a <code>render</code>
* operation. When in the <code>event</code> phase, the action that is executed can't render
* any output. This means that if an action in the XWork configuration is executed in the event
* phase, and the action is set up with a result that should render something, the result can't
* immediately be executed. The portlet needs to "wait" to the render phase to do the
* rendering.
* <p/>
* When the {@link org.apache.struts2.portlet.result.PortletResult} detects such a
* scenario, instead of executing the actual view, it prepares a couple of render parameters
* specifying this action and the location of the view, which then will be executed in the
* following render request.
*/
public class DirectRenderFromEventAction implements Action, Serializable {
private static final long serialVersionUID = -1814807772308405785L;
private String location = null;
/**
* Get the location of the view.
*
* @return Returns the location.
*/
public String getLocation() {
return location;
}
/**
* Set the location of the view.
*
* @param location The location to set.
*/
public void setLocation(String location) {
this.location = location;
}
/**
* Always return success.
*
* @return SUCCESS
*/
public String execute() throws Exception {
return SUCCESS;
}
}
@@ -0,0 +1,608 @@
/*
* $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.dispatcher;
import java.io.IOException;
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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.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.context.ServletContextHolderListener;
import org.apache.struts2.portlet.util.HttpServletRequestMock;
import org.apache.struts2.util.AttributeMap;
import com.opensymphony.xwork2.util.FileManager;
import com.opensymphony.xwork2.util.ValueStack;
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.LocalizedTextUtil;
import com.opensymphony.xwork2.util.TextUtils;
/**
* <!-- 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 <a href="nils-helge.garli@bekk.no">Nils-Helge Garli </a>
* @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 -->
*
* &lt;init-param&gt;
* &lt;!-- The view mode namespace. Maps to a namespace in the xwork config file --&gt;
* &lt;name&gt;viewNamespace&lt;/name&gt;
* &lt;value&gt;/view&lt;/value&gt;
* &lt;/init-param&gt;
* &lt;init-param&gt;
* &lt;!-- The default action to invoke in view mode --&gt;
* &lt;name&gt;defaultViewAction&lt;/name&gt;
* &lt;value&gt;index&lt;/value&gt;
* &lt;/init-param&gt;
* &lt;init-param&gt;
* &lt;!-- The view mode namespace. Maps to a namespace in the xwork config file --&gt;
* &lt;name&gt;editNamespace&lt;/name&gt;
* &lt;value&gt;/edit&lt;/value&gt;
* &lt;/init-param&gt;
* &lt;init-param&gt;
* &lt;!-- The default action to invoke in view mode --&gt;
* &lt;name&gt;defaultEditAction&lt;/name&gt;
* &lt;value&gt;index&lt;/value&gt;
* &lt;/init-param&gt;
* &lt;init-param&gt;
* &lt;!-- The view mode namespace. Maps to a namespace in the xwork config file --&gt;
* &lt;name&gt;helpNamespace&lt;/name&gt;
* &lt;value&gt;/help&lt;/value&gt;
* &lt;/init-param&gt;
* &lt;init-param&gt;
* &lt;!-- The default action to invoke in view mode --&gt;
* &lt;name&gt;defaultHelpAction&lt;/name&gt;
* &lt;value&gt;index&lt;/value&gt;
* &lt;/init-param&gt;
*
* <!-- END SNIPPET: example -->
* </pre>
*/
public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics,
PortletActionConstants {
private static final Log LOG = LogFactory.getLog(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;
/**
* Initialize the portlet with the init parameters from <tt>portlet.xml</tt>
*/
public void init(PortletConfig cfg) throws PortletException {
super.init(cfg);
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);
}
Dispatcher.setPortletSupportActive(true);
dispatcherUtils = new Dispatcher(ServletContextHolderListener.getServletContext(), params);
dispatcherUtils.init();
// For testability
if (factory == null) {
factory = dispatcherUtils.getConfigurationManager().getConfiguration().getContainer().getInstance(ActionProxyFactory.class);
}
portletNamespace = cfg.getInitParameter("portletNamespace");
LOG.debug("PortletNamespace: " + portletNamespace);
parseModeConfig(cfg, PortletMode.VIEW, "viewNamespace",
"defaultViewAction");
parseModeConfig(cfg, PortletMode.EDIT, "editNamespace",
"defaultEditAction");
parseModeConfig(cfg, PortletMode.HELP, "helpNamespace",
"defaultHelpAction");
parseModeConfig(cfg, new PortletMode("config"), "configNamespace",
"defaultConfigAction");
parseModeConfig(cfg, new PortletMode("about"), "aboutNamespace",
"defaultAboutAction");
parseModeConfig(cfg, new PortletMode("print"), "printNamespace",
"defaultPrintAction");
parseModeConfig(cfg, new PortletMode("preview"), "previewNamespace",
"defaultPreviewAction");
parseModeConfig(cfg, new PortletMode("edit_defaults"),
"editDefaultsNamespace", "defaultEditDefaultsAction");
if (!TextUtils.stringSet(portletNamespace)) {
portletNamespace = "";
}
LocalizedTextUtil
.addDefaultResourceBundle("org/apache/struts2/struts-messages");
Container 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 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.
*/
private void parseModeConfig(PortletConfig portletConfig,
PortletMode portletMode, String nameSpaceParam,
String defaultActionParam) {
String namespace = portletConfig.getInitParameter(nameSpaceParam);
if (!TextUtils.stringSet(namespace)) {
namespace = "";
}
modeMap.put(portletMode, namespace);
String defaultAction = portletConfig
.getInitParameter(defaultActionParam);
if (!TextUtils.stringSet(defaultAction)) {
defaultAction = DEFAULT_ACTION_NAME;
}
StringBuffer fullPath = new StringBuffer();
if (TextUtils.stringSet(portletNamespace)) {
fullPath.append(portletNamespace);
}
if (TextUtils.stringSet(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()));
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 {
LOG.debug("Entering processAction");
resetActionContext();
try {
serviceAction(request, response, getActionMapping(request),
getRequestMap(request), getParameterMap(request),
getSessionMap(request), getApplicationMap(),
portletNamespace, EVENT_PHASE);
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 {
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, getActionMapping(request),
getRequestMap(request), getParameterMap(request),
getSessionMap(request), getApplicationMap(),
portletNamespace, RENDER_PHASE);
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 createContextMap(Map requestMap, Map parameterMap,
Map sessionMap, Map applicationMap, PortletRequest request,
PortletResponse response, PortletConfig portletConfig, Integer phase) {
// TODO Must put http request/response objects into map for use with
// ServletActionContext
HashMap<String,Object> extraContext = new HashMap<String,Object>();
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 mapping the action mapping.
* @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,
ActionMapping mapping, Map requestMap, Map parameterMap,
Map sessionMap, Map applicationMap, String portletNamespace,
Integer phase) throws PortletException {
LOG.debug("serviceAction");
HashMap extraContext = createContextMap(requestMap, parameterMap,
sessionMap, applicationMap, request, response,
getPortletConfig(), phase);
String actionName = mapping.getName();
String namespace = mapping.getNamespace();
Dispatcher.setInstance(dispatcherUtils);
try {
LOG.debug("Creating action proxy for name = " + actionName
+ ", namespace = " + namespace);
ActionProxy proxy = factory.createActionProxy(namespace,
actionName, extraContext);
proxy.setMethod(mapping.getMethod());
request.setAttribute("struts.valueStack", proxy.getInvocation()
.getStack());
if (PortletActionConstants.RENDER_PHASE.equals(phase)
&& TextUtils.stringSet(request
.getParameter(EVENT_ACTION))) {
ActionProxy action = (ActionProxy) request.getPortletSession()
.getAttribute(EVENT_ACTION);
if (action != null) {
ValueStack stack = proxy.getInvocation().getStack();
Object top = stack.pop();
stack.push(action.getInvocation().getAction());
stack.push(top);
}
}
proxy.execute();
if (PortletActionConstants.EVENT_PHASE.equals(phase)) {
// Store the executed action in the session for retrieval in the
// render phase.
ActionResponse actionResp = (ActionResponse) response;
request.getPortletSession().setAttribute(EVENT_ACTION, proxy);
actionResp.setRenderParameter(EVENT_ACTION, "true");
}
} 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 request) {
ActionMapping mapping = null;
String actionPath = null;
if (resetAction(request)) {
mapping = (ActionMapping) actionMap.get(request.getPortletMode());
} else {
actionPath = request.getParameter(ACTION_PARAM);
if (!TextUtils.stringSet(actionPath)) {
mapping = (ActionMapping) actionMap.get(request
.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
HttpServletRequestMock httpRequest = new HttpServletRequestMock()
.setServletPath(actionPath + ".action")
.setParameterMap(request.getParameterMap());
mapping = actionMapper.getMapping(httpRequest, 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 getParameterMap(PortletRequest request) throws IOException {
return new HashMap(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&lt;Mode&gt;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;
}
}
return reset;
}
public void destroy() {
if (dispatcherUtils == null) {
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;
}
}
@@ -0,0 +1,39 @@
/*
* $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.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);
}
@@ -0,0 +1,104 @@
/*
* $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.PortletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.StrutsStatics;
import org.apache.struts2.portlet.context.PortletActionContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
/**
* <!-- START SNIPPET: description -->
*
* An interceptor which provides an implementation of PortletPreferences if the Action implements
* PortletPreferencesAware.
*
* If running in a servlet environment, a testing implementation of PortletPreferences will be
* created and provided, but it should not be used in a production environment.
*
* <!-- END SNIPPET: description -->
*
* <p/> <u>Interceptor parameters:</u>
*
* <!-- START SNIPPET: parameters -->
*
* <ul>
*
* <li>None</li>
*
* </ul>
*
* <!-- END SNIPPET: parameters -->
*
* <p/> <u>Extending the interceptor:</u>
*
* <p/>
*
* <!-- START SNIPPET: extending -->
*
* There are no known extension points for this interceptor.
*
* <!-- END SNIPPET: extending -->
*
* <p/> <u>Example code:</u>
*
* <pre>
* <!-- START SNIPPET: example -->
* &lt;action name="someAction" class="com.examples.SomeAction"&gt;
* &lt;interceptor-ref name="portlet-preferences"/&gt;
* &lt;interceptor-ref name="basicStack"/&gt;
* &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
* &lt;/action&gt;
* <!-- END SNIPPET: example -->
* </pre>
*
* @see PortletPreferencesAware
*/
public class PortletPreferencesInterceptor extends AbstractInterceptor implements StrutsStatics {
private static final Log LOG = LogFactory.getLog(PortletPreferencesInterceptor.class);
public String intercept(ActionInvocation invocation) throws Exception {
final Object action = invocation.getAction();
final ActionContext context = invocation.getInvocationContext();
if (action instanceof PortletPreferencesAware) {
PortletRequest request = PortletActionContext.getRequest();
PortletPreferencesAware awareAction = (PortletPreferencesAware) action;
// Check if running in a servlet environment
if (request == null) {
LOG.warn("This portlet preferences implementation should only be used during development");
awareAction.setPortletPreferences(new ServletPortletPreferences(ActionContext.getContext().getSession()));
} else {
awareAction.setPortletPreferences(request.getPreferences());
}
}
return invocation.invoke();
}
}
@@ -0,0 +1,73 @@
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");
}
}
@@ -0,0 +1,95 @@
/*
* $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 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 {
}
}
@@ -0,0 +1,246 @@
/*
* $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.result;
import java.io.IOException;
import java.util.StringTokenizer;
import javax.portlet.ActionResponse;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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 com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.util.TextUtils;
/**
* Result type that includes a JSP to render.
*
*/
public class PortletResult extends StrutsResultSupport {
private static final long serialVersionUID = 434251393926178567L;
/**
* Logger instance.
*/
private static final Log LOG = LogFactory.getLog(PortletResult.class);
private String contentType = "text/html";
private String title;
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) {
LOG.debug("Executing result in Event phase");
ActionResponse res = PortletActionContext.getActionResponse();
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(PortletActionConstants.ACTION_PARAM, finalLocation);
} else {
// View is rendered outside an action...uh oh...
res.setRenderParameter(PortletActionConstants.ACTION_PARAM, "renderDirect");
res.setRenderParameter("location", finalLocation);
}
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 {
LOG.debug("Executing result in Render phase");
PortletConfig cfg = PortletActionContext.getPortletConfig();
RenderRequest req = PortletActionContext.getRenderRequest();
RenderResponse res = PortletActionContext.getRenderResponse();
LOG.debug("PortletConfig: " + cfg);
LOG.debug("RenderRequest: " + req);
LOG.debug("RenderResponse: " + res);
res.setContentType(contentType);
if (TextUtils.stringSet(title)) {
res.setTitle(title);
}
LOG.debug("Location: " + finalLocation);
PortletRequestDispatcher preparator = cfg.getPortletContext()
.getNamedDispatcher("preparator");
if(preparator == null) {
throw new PortletException("Cannot look up 'preparator' servlet. Make sure that you" +
"have configured it correctly in the web.xml file.");
}
new IncludeTemplate() {
protected void when(PortletException e) {
LOG.error("PortletException while dispatching to 'preparator' servlet", e);
}
protected void when(IOException e) {
LOG.error("IOException while dispatching to 'preparator' servlet", e);
}
}.include(preparator, req, res);
PortletRequestDispatcher dispatcher = cfg.getPortletContext().getRequestDispatcher(finalLocation);
if(dispatcher == null) {
throw new PortletException("Could not locate dispatcher for '" + finalLocation + "'");
}
new IncludeTemplate() {
protected void when(PortletException e) {
LOG.error("PortletException while dispatching to '" + finalLocation + "'");
}
protected void when(IOException e) {
LOG.error("IOException while dispatching to '" + finalLocation + "'");
}
}.include(dispatcher, 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;
}
static class IncludeTemplate {
protected void include(PortletRequestDispatcher dispatcher, RenderRequest req, RenderResponse res) throws PortletException, IOException{
try {
dispatcher.include(req, res);
}
catch(PortletException e) {
when(e);
throw e;
}
catch(IOException e) {
when(e);
throw e;
}
}
protected void when(PortletException e) {}
protected void when(IOException e) {}
}
}
@@ -0,0 +1,307 @@
/*
* $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.result;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletRequestDispatcher;
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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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 com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.ValueStack;
/**
* <!-- 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>
* &lt;!-- START SNIPPET: example --&gt;
* &lt;result name=&quot;success&quot; type=&quot;velocity&quot;&gt;
* &lt;param name=&quot;location&quot;&gt;foo.vm&lt;/param&gt;
* &lt;/result&gt;
* &lt;!-- END SNIPPET: example --&gt;
* </pre>
*
*/
public class PortletVelocityResult extends StrutsResultSupport {
private static final long serialVersionUID = -8241086555872212274L;
private static final Log log = LogFactory
.getLog(PortletVelocityResult.class);
private String defaultEncoding;
private VelocityManager velocityManager;
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...
res.setRenderParameter(PortletActionConstants.ACTION_PARAM,
"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 {
prepareServletActionContext();
ValueStack stack = ActionContext.getContext().getValueStack();
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
JspFactory jspFactory = null;
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) {
jspFactory = JspFactory.getDefaultFactory();
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;
}
Template t = getTemplate(stack,
velocityManager.getVelocityEngine(), invocation,
finalLocation, encoding);
Context context = createContext(velocityManager, stack, request,
response, finalLocation);
Writer writer = new OutputStreamWriter(response.getOutputStream(),
encoding);
response.setContentType(contentType);
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);
}
/**
* Prepares the servlet action context for this request
*/
private void prepareServletActionContext() throws PortletException,
IOException {
PortletRequestDispatcher disp = PortletActionContext.getPortletConfig()
.getPortletContext().getNamedDispatcher("preparator");
disp.include(PortletActionContext.getRenderRequest(),
PortletActionContext.getRenderResponse());
}
}
@@ -0,0 +1,278 @@
/*
* $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.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* A simple mock class to interact with Struts 2 API's that require a servlet request
*/
public class HttpServletRequestMock implements HttpServletRequest {
private String servletPath;
private Map parameterMap;
public String getAuthType() {
return null;
}
public String getContextPath() {
return null;
}
public Cookie[] getCookies() {
return null;
}
public long getDateHeader(String arg0) {
return 0;
}
public String getHeader(String arg0) {
return null;
}
public Enumeration getHeaderNames() {
return null;
}
public Enumeration getHeaders(String arg0) {
return null;
}
public int getIntHeader(String arg0) {
return 0;
}
public String getMethod() {
return null;
}
public String getPathInfo() {
return null;
}
public String getPathTranslated() {
return null;
}
public String getQueryString() {
return null;
}
public String getRemoteUser() {
return null;
}
public String getRequestURI() {
return null;
}
public StringBuffer getRequestURL() {
return null;
}
public String getRequestedSessionId() {
return null;
}
public String getServletPath() {
return servletPath;
}
public HttpSession getSession() {
return null;
}
public HttpSession getSession(boolean arg0) {
return null;
}
public Principal getUserPrincipal() {
return null;
}
public boolean isRequestedSessionIdFromCookie() {
return false;
}
public boolean isRequestedSessionIdFromURL() {
return false;
}
public boolean isRequestedSessionIdFromUrl() {
return false;
}
public boolean isRequestedSessionIdValid() {
return false;
}
public boolean isUserInRole(String arg0) {
return false;
}
public Object getAttribute(String arg0) {
return null;
}
public Enumeration getAttributeNames() {
return null;
}
public String getCharacterEncoding() {
return null;
}
public int getContentLength() {
return 0;
}
public String getContentType() {
return null;
}
public ServletInputStream getInputStream() throws IOException {
return null;
}
public String getLocalAddr() {
return null;
}
public String getLocalName() {
return null;
}
public int getLocalPort() {
return 0;
}
public Locale getLocale() {
return null;
}
public Enumeration getLocales() {
return null;
}
public String getParameter(String arg0) {
return null;
}
public Map getParameterMap() {
return parameterMap;
}
public Enumeration getParameterNames() {
return null;
}
public String[] getParameterValues(String arg0) {
return null;
}
public String getProtocol() {
return null;
}
public BufferedReader getReader() throws IOException {
return null;
}
public String getRealPath(String arg0) {
return null;
}
public String getRemoteAddr() {
return null;
}
public String getRemoteHost() {
return null;
}
public int getRemotePort() {
return 0;
}
public RequestDispatcher getRequestDispatcher(String arg0) {
return null;
}
public String getScheme() {
return null;
}
public String getServerName() {
return null;
}
public int getServerPort() {
return 0;
}
public boolean isSecure() {
return false;
}
public void removeAttribute(String arg0) {
}
public void setAttribute(String arg0, Object arg1) {
}
public void setCharacterEncoding(String arg0)
throws UnsupportedEncodingException {
}
/**
* @param parameterMap the parameterMap to set
*/
public HttpServletRequestMock setParameterMap(Map parameterMap) {
this.parameterMap = parameterMap;
return this;
}
/**
* @param servletPath the servletPath to set
*/
public HttpServletRequestMock setServletPath(String servletPath) {
this.servletPath = servletPath;
return this;
}
}
@@ -0,0 +1,302 @@
/*
* $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.util;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.StringTokenizer;
import javax.portlet.PortletMode;
import javax.portlet.PortletSecurityException;
import javax.portlet.PortletURL;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.WindowState;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.StrutsException;
import org.apache.struts2.portlet.PortletActionConstants;
import org.apache.struts2.portlet.context.PortletActionContext;
import com.opensymphony.xwork2.util.TextUtils;
/**
* 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.
*
*/
public class PortletUrlHelper {
public static final String ENCODING = "UTF-8";
private static final Log LOG = LogFactory.getLog(PortletUrlHelper.class);
/**
* Create a portlet URL with for the specified action and namespace.
*
* @param action The action the URL should invoke.
* @param namespace The namespace of the action to invoke.
* @param params The parameters of the URL.
* @param type The type of the url, either <tt>action</tt> or <tt>render</tt>
* @param mode The PortletMode of the URL.
* @param state The WindowState of the URL.
* @return The URL String.
*/
public static String buildUrl(String action, String namespace, Map params,
String type, String mode, String state) {
return buildUrl(action, namespace, params, null, type, mode, state,
true, true);
}
/**
* Create a portlet URL with for the specified action and namespace.
*
* @see #buildUrl(String, String, Map, String, String, String)
*/
public static String buildUrl(String action, String namespace, Map params,
String scheme, String type, String portletMode, String windowState,
boolean includeContext, boolean encodeResult) {
RenderRequest request = PortletActionContext.getRenderRequest();
RenderResponse response = PortletActionContext.getRenderResponse();
LOG.debug("Creating url. Action = " + action + ", Namespace = "
+ namespace + ", Type = " + type);
namespace = prependNamespace(namespace, portletMode);
if (!TextUtils.stringSet(portletMode)) {
portletMode = PortletActionContext.getRenderRequest().getPortletMode().toString();
}
String result = null;
int paramStartIndex = action.indexOf('?');
if (paramStartIndex > 0) {
String value = action;
action = value.substring(0, value.indexOf('?'));
String queryStr = value.substring(paramStartIndex + 1);
StringTokenizer tok = new StringTokenizer(queryStr, "&");
while (tok.hasMoreTokens()) {
String paramVal = tok.nextToken();
String key = paramVal.substring(0, paramVal.indexOf('='));
String val = paramVal.substring(paramVal.indexOf('=') + 1);
params.put(key, new String[] { val });
}
}
if (TextUtils.stringSet(namespace)) {
StringBuffer sb = new StringBuffer();
sb.append(namespace);
if(!action.startsWith("/") && !namespace.endsWith("/")) {
sb.append("/");
}
action = sb.append(action).toString();
LOG.debug("Resulting actionPath: " + action);
}
params.put(PortletActionConstants.ACTION_PARAM, new String[] { action });
PortletURL url = null;
if ("action".equalsIgnoreCase(type)) {
LOG.debug("Creating action url");
url = response.createActionURL();
} else {
LOG.debug("Creating render url");
url = response.createRenderURL();
}
params.put(PortletActionConstants.MODE_PARAM, portletMode);
url.setParameters(ensureParamsAreStringArrays(params));
if ("HTTPS".equalsIgnoreCase(scheme)) {
try {
url.setSecure(true);
} catch (PortletSecurityException e) {
LOG.error("Cannot set scheme to https", e);
}
}
try {
url.setPortletMode(getPortletMode(request, portletMode));
url.setWindowState(getWindowState(request, windowState));
} catch (Exception e) {
LOG.error("Unable to set mode or state:" + e.getMessage(), e);
}
result = url.toString();
// TEMP BUG-WORKAROUND FOR DOUBLE ESCAPING OF AMPERSAND
if(result.indexOf("&amp;") >= 0) {
result = result.replace("&amp;", "&");
}
return result;
}
/**
*
* Prepend the namespace configuration for the specified namespace and PortletMode.
*
* @param namespace The base namespace.
* @param portletMode The PortletMode.
*
* @return prepended namespace.
*/
private static String prependNamespace(String namespace, String portletMode) {
StringBuffer sb = new StringBuffer();
PortletMode mode = PortletActionContext.getRenderRequest().getPortletMode();
if(TextUtils.stringSet(portletMode)) {
mode = new PortletMode(portletMode);
}
String portletNamespace = PortletActionContext.getPortletNamespace();
String modeNamespace = (String)PortletActionContext.getModeNamespaceMap().get(mode);
LOG.debug("PortletNamespace: " + portletNamespace + ", modeNamespace: " + modeNamespace);
if(TextUtils.stringSet(portletNamespace)) {
sb.append(portletNamespace);
}
if(TextUtils.stringSet(modeNamespace)) {
if(!modeNamespace.startsWith("/")) {
sb.append("/");
}
sb.append(modeNamespace);
}
if(TextUtils.stringSet(namespace)) {
if(!namespace.startsWith("/")) {
sb.append("/");
}
sb.append(namespace);
}
LOG.debug("Resulting namespace: " + sb);
return sb.toString();
}
/**
* Encode an url to a non Struts action resource, like stylesheet, image or
* servlet.
*
* @param value
* @return encoded url to non Struts action resources.
*/
public static String buildResourceUrl(String value, Map params) {
StringBuffer sb = new StringBuffer();
// Relative URLs are not allowed in a portlet
if (!value.startsWith("/")) {
sb.append("/");
}
sb.append(value);
if(params != null && params.size() > 0) {
sb.append("?");
Iterator it = params.keySet().iterator();
try {
while(it.hasNext()) {
String key = (String)it.next();
String val = (String)params.get(key);
sb.append(URLEncoder.encode(key, ENCODING)).append("=");
sb.append(URLEncoder.encode(val, ENCODING));
if(it.hasNext()) {
sb.append("&");
}
}
} catch (UnsupportedEncodingException e) {
throw new StrutsException("Encoding "+ENCODING+" not found");
}
}
RenderResponse resp = PortletActionContext.getRenderResponse();
RenderRequest req = PortletActionContext.getRenderRequest();
return resp.encodeURL(req.getContextPath() + sb.toString());
}
/**
* Will ensure that all entries in <code>params</code> are String arrays,
* as requried by the setParameters on the PortletURL.
*
* @param params The parameters to the URL.
* @return A Map with all parameters as String arrays.
*/
public static Map ensureParamsAreStringArrays(Map params) {
Map result = null;
if (params != null) {
result = new LinkedHashMap(params.size());
Iterator it = params.keySet().iterator();
while (it.hasNext()) {
Object key = it.next();
Object val = params.get(key);
if (val instanceof String[]) {
result.put(key, val);
} else {
result.put(key, new String[] { val.toString() });
}
}
}
return result;
}
/**
* Convert the given String to a WindowState object.
*
* @param portletReq The RenderRequest.
* @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,
String windowState) {
WindowState state = portletReq.getWindowState();
if (TextUtils.stringSet(windowState)) {
state = portletReq.getWindowState();
if ("maximized".equalsIgnoreCase(windowState)) {
state = WindowState.MAXIMIZED;
} else if ("normal".equalsIgnoreCase(windowState)) {
state = WindowState.NORMAL;
} else if ("minimized".equalsIgnoreCase(windowState)) {
state = WindowState.MINIMIZED;
}
}
if(state == null) {
state = WindowState.NORMAL;
}
return state;
}
/**
* Convert the given String to a PortletMode object.
*
* @param portletReq The RenderRequest.
* @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,
String portletMode) {
PortletMode mode = portletReq.getPortletMode();
if (TextUtils.stringSet(portletMode)) {
mode = portletReq.getPortletMode();
if ("edit".equalsIgnoreCase(portletMode)) {
mode = PortletMode.EDIT;
} else if ("view".equalsIgnoreCase(portletMode)) {
mode = PortletMode.VIEW;
} else if ("help".equalsIgnoreCase(portletMode)) {
mode = PortletMode.HELP;
}
}
if(mode == null) {
mode = PortletMode.VIEW;
}
return mode;
}
}
@@ -0,0 +1,293 @@
/*
* $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.views.freemarker;
import java.io.IOException;
import java.io.Writer;
import java.util.Locale;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletRequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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 org.apache.struts2.views.util.ResourceUtil;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.ValueStack;
import freemarker.template.Configuration;
import freemarker.template.ObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
/**
*/
public class PortletFreemarkerResult extends StrutsResultSupport {
private static final long serialVersionUID = -5570612389289887543L;
protected ActionInvocation invocation;
protected Configuration configuration;
protected ObjectWrapper wrapper;
protected FreemarkerManager freemarkerManager;
/*
* Struts results are constructed for each result execeution
*
* the current context is availible to subclasses via these protected fields
*/
protected String location;
private String pContentType = "text/html";
public PortletFreemarkerResult() {
super();
}
public PortletFreemarkerResult(String location) {
super(location);
}
@Inject
public void setFreemarkerManager(FreemarkerManager mgr) {
this.freemarkerManager = mgr;
}
public void setContentType(String aContentType) {
pContentType = aContentType;
}
/**
* allow parameterization of the contentType the default being text/html
*/
public String getContentType() {
return pContentType;
}
/**
* Execute this result, using the specified template location. <p/>The
* template location has already been interoplated for any variable
* substitutions <p/>this method obtains the freemarker configuration and
* the object wrapper from the provided hooks. It them implements the
* template processing workflow by calling the hooks for preTemplateProcess
* and postTemplateProcess
*/
public void doExecute(String location, ActionInvocation invocation)
throws IOException, TemplateException, PortletException {
if (PortletActionContext.isEvent()) {
executeActionResult(location, invocation);
} else if (PortletActionContext.isRender()) {
executeRenderResult(location, invocation);
}
}
/**
* @param location
* @param invocation
*/
private void executeActionResult(String location,
ActionInvocation invocation) {
ActionResponse res = PortletActionContext.getActionResponse();
// View is rendered outside an action...uh oh...
res.setRenderParameter(PortletActionConstants.ACTION_PARAM, "freemarkerDirect");
res.setRenderParameter("location", location);
res.setRenderParameter(PortletActionConstants.MODE_PARAM, PortletActionContext
.getRequest().getPortletMode().toString());
}
/**
* @param location
* @param invocation
* @throws TemplateException
* @throws IOException
* @throws TemplateModelException
*/
private void executeRenderResult(String location,
ActionInvocation invocation) throws TemplateException, IOException,
TemplateModelException, PortletException {
prepareServletActionContext();
this.location = location;
this.invocation = invocation;
this.configuration = getConfiguration();
this.wrapper = getObjectWrapper();
HttpServletRequest req = ServletActionContext.getRequest();
if (!location.startsWith("/")) {
String base = ResourceUtil.getResourceBase(req);
location = base + "/" + location;
}
Template template = configuration.getTemplate(location, deduceLocale());
TemplateModel model = createModel();
// Give subclasses a chance to hook into preprocessing
if (preTemplateProcess(template, model)) {
try {
// Process the template
PortletActionContext.getRenderResponse().setContentType(pContentType);
template.process(model, getWriter());
} finally {
// Give subclasses a chance to hook into postprocessing
postTemplateProcess(template, model);
}
}
}
/**
*
*/
private void prepareServletActionContext() throws PortletException,
IOException {
PortletRequestDispatcher disp = PortletActionContext.getPortletConfig()
.getPortletContext().getNamedDispatcher("preparator");
disp.include(PortletActionContext.getRenderRequest(),
PortletActionContext.getRenderResponse());
}
/**
* This method is called from {@link #doExecute(String, ActionInvocation)}
* to obtain the FreeMarker configuration object that this result will use
* for template loading. This is a hook that allows you to custom-configure
* the configuration object in a subclass, or to fetch it from an IoC
* container. <p/><b>The default implementation obtains the configuration
* from the ConfigurationManager instance. </b>
*/
protected Configuration getConfiguration() throws TemplateException {
return freemarkerManager.getConfiguration(
ServletActionContext.getServletContext());
}
/**
* This method is called from {@link #doExecute(String, ActionInvocation)}
* to obtain the FreeMarker object wrapper object that this result will use
* for adapting objects into template models. This is a hook that allows you
* to custom-configure the wrapper object in a subclass. <p/><b>The default
* implementation returns {@link Configuration#getObjectWrapper()}</b>
*/
protected ObjectWrapper getObjectWrapper() {
return configuration.getObjectWrapper();
}
/**
* The default writer writes directly to the response writer.
*/
protected Writer getWriter() throws IOException {
return PortletActionContext.getRenderResponse().getWriter();
}
/**
* Build the instance of the ScopesHashModel, including JspTagLib support
* <p/>Objects added to the model are <p/>
* <ul>
* <li>Application - servlet context attributes hash model
* <li>JspTaglibs - jsp tag lib factory model
* <li>Request - request attributes hash model
* <li>Session - session attributes hash model
* <li>request - the HttpServletRequst object for direct access
* <li>response - the HttpServletResponse object for direct access
* <li>stack - the OgnLValueStack instance for direct access
* <li>ognl - the instance of the OgnlTool
* <li>action - the action itself
* <li>exception - optional : the JSP or Servlet exception as per the
* servlet spec (for JSP Exception pages)
* <li>struts - instance of the StrutsUtil class
* </ul>
*/
protected TemplateModel createModel() throws TemplateModelException {
ServletContext servletContext = ServletActionContext
.getServletContext();
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
ValueStack stack = ServletActionContext.getContext()
.getValueStack();
return freemarkerManager.buildTemplateModel(stack,
invocation.getAction(), servletContext, request, response,
wrapper);
}
/**
* Returns the locale used for the
* {@link Configuration#getTemplate(String, Locale)}call. The base
* implementation simply returns the locale setting of the configuration.
* Override this method to provide different behaviour,
*/
protected Locale deduceLocale() {
return configuration.getLocale();
}
/**
* the default implementation of postTemplateProcess applies the contentType
* parameter
*/
protected void postTemplateProcess(Template template, TemplateModel data)
throws IOException {
}
/**
* Called before the execution is passed to template.process(). This is a
* generic hook you might use in subclasses to perform a specific action
* before the template is processed. By default does nothing. A typical
* action to perform here is to inject application-specific objects into the
* model root
*
* @return true to process the template, false to suppress template
* processing.
*/
protected boolean preTemplateProcess(Template template, TemplateModel model)
throws IOException {
Object attrContentType = template.getCustomAttribute("content_type");
if (attrContentType != null) {
ServletActionContext.getResponse().setContentType(
attrContentType.toString());
} else {
String contentType = getContentType();
if (contentType == null) {
contentType = "text/html";
}
String encoding = template.getEncoding();
if (encoding != null) {
contentType = contentType + "; charset=" + encoding;
}
ServletActionContext.getResponse().setContentType(contentType);
}
return true;
}
}
@@ -0,0 +1,174 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
@@ -0,0 +1,5 @@
Apache Struts
Copyright 2000-2007 The Apache Software Foundation
This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<bean type="org.apache.struts2.components.UrlRenderer" name="portlet" class="org.apache.struts2.components.PortletUrlRenderer"/>
<constant name="struts.urlRenderer" value="portlet" />
<package name="struts-portlet-default" extends="struts-default">
<result-types>
<result-type name="dispatcher" class="org.apache.struts2.portlet.result.PortletResult" default="true"/>
<result-type name="freemarker" class="org.apache.struts2.views.freemarker.PortletFreemarkerResult"/>
<result-type name="velocity" class="org.apache.struts2.portlet.result.PortletVelocityResult"/>
</result-types>
<interceptors>
<interceptor name="portlet-preferences" class="org.apache.struts2.portlet.interceptor.PortletPreferencesInterceptor"/>
<interceptor name="servletConfig" class="org.apache.struts2.portlet.interceptor.PortletConfigInterceptor"/>
<interceptor-stack name="portletDefaultStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="portlet-preferences" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="portletDefaultStack"/>
<action name="renderDirect" class="org.apache.struts2.portlet.dispatcher.DirectRenderFromEventAction">
<result name="success">${location}</result>
</action>
<action name="freemarkerDirect" class="org.apache.struts2.portlet.dispatcher.DirectRenderFromEventAction">
<result type="freemarker" name="success">${location}</result>
</action>
<action name="velocityDirect" class="org.apache.struts2.portlet.dispatcher.DirectRenderFromEventAction">
<result type="velocity" name="success">${location}</result>
</action>
</package>
</struts>
@@ -0,0 +1,169 @@
/*
* $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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.portlet.PortletContext;
import org.jmock.Mock;
import org.jmock.MockObjectTestCase;
import org.jmock.core.Constraint;
/**
*/
public class PortletApplicationMapTest extends MockObjectTestCase {
Mock mockPortletContext;
PortletContext portletContext;
public void setUp() throws Exception {
super.setUp();
mockPortletContext = mock(PortletContext.class);
portletContext = (PortletContext) mockPortletContext.proxy();
}
public void testGetFromAttributes() {
mockPortletContext.stubs().method("getAttribute").with(eq("dummyKey"))
.will(returnValue("dummyValue"));
PortletApplicationMap map = new PortletApplicationMap(
(PortletContext) mockPortletContext.proxy());
assertEquals("dummyValue", map.get("dummyKey"));
}
public void testGetFromInitParameters() {
mockPortletContext.stubs().method("getAttribute").with(eq("dummyKey"));
mockPortletContext.stubs().method("getInitParameter").with(
eq("dummyKey")).will(returnValue("dummyValue"));
PortletApplicationMap map = new PortletApplicationMap(
(PortletContext) mockPortletContext.proxy());
assertEquals("dummyValue", map.get("dummyKey"));
}
public void testPut() {
mockPortletContext.expects(once()).method("setAttribute").with(
new Constraint[] { eq("dummyKey"), eq("dummyValue") });
mockPortletContext.expects(once()).method("getAttribute").with(
eq("dummyKey")).will(returnValue("dummyValue"));
PortletApplicationMap map = new PortletApplicationMap(portletContext);
Object val = map.put("dummyKey", "dummyValue");
assertEquals("dummyValue", val);
}
public void testRemove() {
mockPortletContext.expects(once()).method("getAttribute").with(
eq("dummyKey")).will(returnValue("dummyValue"));
mockPortletContext.expects(once()).method("removeAttribute").with(
eq("dummyKey"));
PortletApplicationMap map = new PortletApplicationMap(portletContext);
Object val = map.remove("dummyKey");
assertEquals("dummyValue", val);
}
public void testEntrySet() {
Enumeration names = new Enumeration() {
List keys = Arrays.asList(new Object[] { "key1", "key2" });
Iterator it = keys.iterator();
public boolean hasMoreElements() {
return it.hasNext();
}
public Object nextElement() {
return it.next();
}
};
Enumeration initParamNames = new Enumeration() {
List keys = Arrays.asList(new Object[] { "key3" });
Iterator it = keys.iterator();
public boolean hasMoreElements() {
return it.hasNext();
}
public Object nextElement() {
return it.next();
}
};
mockPortletContext.stubs().method("getAttributeNames").will(
returnValue(names));
mockPortletContext.stubs().method("getInitParameterNames").will(
returnValue(initParamNames));
mockPortletContext.stubs().method("getAttribute").with(eq("key1"))
.will(returnValue("value1"));
mockPortletContext.stubs().method("getAttribute").with(eq("key2"))
.will(returnValue("value2"));
mockPortletContext.stubs().method("getInitParameter").with(eq("key3"))
.will(returnValue("value3"));
PortletApplicationMap map = new PortletApplicationMap(portletContext);
Set entries = map.entrySet();
assertEquals(3, entries.size());
Iterator it = entries.iterator();
Map.Entry entry = (Map.Entry) it.next();
assertEquals("key2", entry.getKey());
assertEquals("value2", entry.getValue());
entry = (Map.Entry) it.next();
assertEquals("key1", entry.getKey());
assertEquals("value1", entry.getValue());
entry = (Map.Entry) it.next();
assertEquals("key3", entry.getKey());
assertEquals("value3", entry.getValue());
}
public void testClear() {
mockPortletContext.expects(once()).method("removeAttribute").with(eq("key1"));
mockPortletContext.expects(once()).method("removeAttribute").with(eq("key2"));
ArrayList dummy = new ArrayList();
dummy.add("key1");
dummy.add("key2");
mockPortletContext.expects(once()).method("getAttributeNames").will(
returnValue(Collections.enumeration(dummy)));
PortletApplicationMap map = new PortletApplicationMap(portletContext);
map.clear();
}
}
@@ -0,0 +1,140 @@
/*
* $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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.portlet.PortletRequest;
import org.jmock.Mock;
import org.jmock.MockObjectTestCase;
import org.jmock.core.Constraint;
/**
* PortletRequestMapTest. Insert description.
*
*/
public class PortletRequestMapTest extends MockObjectTestCase {
public void testSetAttribute() {
}
public void testGet() {
Mock mockRequest = mock(PortletRequest.class, "testGet");
mockRequest.expects(once()).method("getAttribute").with(eq("testAttribute")).will(returnValue("testValue"));
PortletRequestMap map = new PortletRequestMap((PortletRequest)mockRequest.proxy());
String value = (String)map.get("testAttribute");
mockRequest.verify();
assertEquals("testValue", value);
}
public void testPut() {
Mock mockRequest = mock(PortletRequest.class, "testPut");
Object value = new String("testValue");
Constraint[] params = new Constraint[]{eq("testAttribute"), eq(value)};
mockRequest.expects(once()).method("setAttribute").with(params);
mockRequest.expects(once()).method("getAttribute").with(eq("testAttribute")).will(returnValue(value));
PortletRequestMap map = new PortletRequestMap((PortletRequest)mockRequest.proxy());
Object obj = map.put("testAttribute", value);
mockRequest.verify();
assertEquals(obj, value);
}
public void testClear() {
Mock mockRequest = mock(PortletRequest.class, "testClear");
mockRequest.expects(once()).method("removeAttribute").with(eq("a"));
mockRequest.expects(once()).method("removeAttribute").with(eq("b"));
ArrayList dummy = new ArrayList();
dummy.add("a");
dummy.add("b");
mockRequest.expects(once()).method("getAttributeNames").will(returnValue(Collections.enumeration(dummy)));
PortletRequestMap map = new PortletRequestMap((PortletRequest)mockRequest.proxy());
map.clear();
mockRequest.verify();
}
public void testRemove() {
Mock mockRequest = mock(PortletRequest.class);
PortletRequest req = (PortletRequest)mockRequest.proxy();
mockRequest.expects(once()).method("getAttribute").with(eq("dummyKey")).will(returnValue("dummyValue"));
mockRequest.expects(once()).method("removeAttribute").with(eq("dummyKey"));
PortletRequestMap map = new PortletRequestMap(req);
Object ret = map.remove("dummyKey");
assertEquals("dummyValue", ret);
}
public void testEntrySet() {
Mock mockRequest = mock(PortletRequest.class);
PortletRequest req = (PortletRequest)mockRequest.proxy();
Enumeration names = new Enumeration() {
List keys = Arrays.asList(new Object[]{"key1", "key2"});
Iterator it = keys.iterator();
public boolean hasMoreElements() {
return it.hasNext();
}
public Object nextElement() {
return it.next();
}
};
mockRequest.stubs().method("getAttributeNames").will(returnValue(names));
mockRequest.stubs().method("getAttribute").with(eq("key1")).will(returnValue("value1"));
mockRequest.stubs().method("getAttribute").with(eq("key2")).will(returnValue("value2"));
PortletRequestMap map = new PortletRequestMap(req);
Set entries = map.entrySet();
assertEquals(2, entries.size());
Iterator it = entries.iterator();
Map.Entry entry = (Map.Entry)it.next();
assertEquals("key2", entry.getKey());
assertEquals("value2", entry.getValue());
entry = (Map.Entry)it.next();
assertEquals("key1", entry.getKey());
assertEquals("value1", entry.getValue());
}
}
@@ -0,0 +1,157 @@
/*
* $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;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;
import org.jmock.Mock;
import org.jmock.MockObjectTestCase;
import org.jmock.core.Constraint;
/**
* PortletSessionMapTest. Insert description.
*
*/
public class PortletSessionMapTest extends MockObjectTestCase {
public void testPut() {
Mock mockSession = mock(PortletSession.class);
Mock mockRequest = mock(PortletRequest.class);
PortletRequest req = (PortletRequest)mockRequest.proxy();
PortletSession session = (PortletSession)mockSession.proxy();
mockRequest.expects(once()).method("getPortletSession").will(returnValue(session));
Constraint[] params = new Constraint[]{eq("testAttribute1"), eq("testValue1")};
mockSession.expects(once()).method("setAttribute").with(params);
mockSession.expects(once()).method("getAttribute").with(eq("testAttribute1")).will(returnValue("testValue1"));
params = new Constraint[]{eq("testAttribute2"), eq("testValue2")};
mockSession.expects(once()).method("setAttribute").with(params);
mockSession.expects(once()).method("getAttribute").with(eq("testAttribute2")).will(returnValue("testValue2"));
PortletSessionMap map = new PortletSessionMap(req);
map.put("testAttribute1", "testValue1");
map.put("testAttribute2", "testValue2");
}
public void testGet() {
Mock mockSession = mock(PortletSession.class);
Mock mockRequest = mock(PortletRequest.class);
PortletRequest req = (PortletRequest)mockRequest.proxy();
PortletSession session = (PortletSession)mockSession.proxy();
mockRequest.expects(once()).method("getPortletSession").will(returnValue(session));
mockSession.expects(once()).method("getAttribute").with(eq("testAttribute1")).will(returnValue("testValue1"));
mockSession.expects(once()).method("getAttribute").with(eq("testAttribute2")).will(returnValue("testValue2"));
PortletSessionMap map = new PortletSessionMap(req);
Object val1 = map.get("testAttribute1");
Object val2 = map.get("testAttribute2");
assertEquals("testValue1", val1);
assertEquals("testValue2", val2);
}
public void testClear() {
Mock mockSession = mock(PortletSession.class);
Mock mockRequest = mock(PortletRequest.class);
PortletRequest req = (PortletRequest)mockRequest.proxy();
PortletSession session = (PortletSession)mockSession.proxy();
mockRequest.expects(once()).method("getPortletSession").will(returnValue(session));
mockSession.expects(once()).method("invalidate");
PortletSessionMap map = new PortletSessionMap(req);
map.clear();
}
public void testRemove() {
Mock mockSession = mock(PortletSession.class);
Mock mockRequest = mock(PortletRequest.class);
PortletRequest req = (PortletRequest)mockRequest.proxy();
PortletSession session = (PortletSession)mockSession.proxy();
mockRequest.expects(once()).method("getPortletSession").will(returnValue(session));
mockSession.stubs().method("getAttribute").with(eq("dummyKey")).will(returnValue("dummyValue"));
mockSession.expects(once()).method("removeAttribute").with(eq("dummyKey"));
PortletSessionMap map = new PortletSessionMap(req);
Object ret = map.remove("dummyKey");
assertEquals("dummyValue", ret);
}
public void testEntrySet() {
Mock mockSession = mock(PortletSession.class);
Mock mockRequest = mock(PortletRequest.class);
PortletRequest req = (PortletRequest)mockRequest.proxy();
PortletSession session = (PortletSession)mockSession.proxy();
Enumeration names = new Enumeration() {
List keys = Arrays.asList(new Object[]{"key1", "key2"});
Iterator it = keys.iterator();
public boolean hasMoreElements() {
return it.hasNext();
}
public Object nextElement() {
return it.next();
}
};
mockSession.stubs().method("getAttributeNames").will(returnValue(names));
mockSession.stubs().method("getAttribute").with(eq("key1")).will(returnValue("value1"));
mockSession.stubs().method("getAttribute").with(eq("key2")).will(returnValue("value2"));
mockRequest.expects(once()).method("getPortletSession").will(returnValue(session));
PortletSessionMap map = new PortletSessionMap(req);
Set entries = map.entrySet();
assertEquals(2, entries.size());
Iterator it = entries.iterator();
Map.Entry entry = (Map.Entry)it.next();
assertEquals("key2", entry.getKey());
assertEquals("value2", entry.getValue());
entry = (Map.Entry)it.next();
assertEquals("key1", entry.getKey());
assertEquals("value1", entry.getValue());
}
}
@@ -0,0 +1,183 @@
/*
* $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.context;
import java.util.HashMap;
import java.util.Map;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletConfig;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import junit.textui.TestRunner;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.portlet.PortletActionConstants;
import org.jmock.Mock;
import org.jmock.MockObjectTestCase;
import com.opensymphony.xwork2.ActionContext;
/**
*/
public class PortletActionContextTest extends MockObjectTestCase {
Mock mockRenderRequest;
Mock mockRenderResponse;
Mock mockPortletConfig;
Mock mockActionRequest;
Mock mockActionResponse;
RenderRequest renderRequest;
RenderResponse renderResponse;
ActionRequest actionRequest;
ActionResponse actionResponse;
PortletConfig portletConfig;
Map context = new HashMap();
public void setUp() throws Exception {
super.setUp();
mockRenderRequest = mock(RenderRequest.class);
mockRenderResponse = mock(RenderResponse.class);
mockActionRequest = mock(ActionRequest.class);
mockActionResponse = mock(ActionResponse.class);
mockPortletConfig = mock(PortletConfig.class);
renderRequest = (RenderRequest)mockRenderRequest.proxy();
renderResponse = (RenderResponse)mockRenderResponse.proxy();
actionRequest = (ActionRequest)mockActionRequest.proxy();
actionResponse = (ActionResponse)mockActionResponse.proxy();
portletConfig = (PortletConfig)mockPortletConfig.proxy();
ActionContext.setContext(new ActionContext(context));
}
public void testGetPhase() {
context.put(PortletActionConstants.PHASE, PortletActionConstants.RENDER_PHASE);
assertEquals(PortletActionConstants.RENDER_PHASE, PortletActionContext.getPhase());
}
public void testIsRender() {
context.put(PortletActionConstants.PHASE, PortletActionConstants.RENDER_PHASE);
assertTrue(PortletActionContext.isRender());
assertFalse(PortletActionContext.isEvent());
}
public void testIsEvent() {
context.put(PortletActionConstants.PHASE, PortletActionConstants.EVENT_PHASE);
assertTrue(PortletActionContext.isEvent());
assertFalse(PortletActionContext.isRender());
}
public void testGetPortletConfig() {
context.put(PortletActionConstants.PORTLET_CONFIG, portletConfig);
assertSame(portletConfig, PortletActionContext.getPortletConfig());
}
public void testGetRenderRequestAndResponse() {
context.put(PortletActionConstants.REQUEST, renderRequest);
context.put(PortletActionConstants.RESPONSE, renderResponse);
context.put(PortletActionConstants.PHASE, PortletActionConstants.RENDER_PHASE);
assertSame(renderRequest, PortletActionContext.getRenderRequest());
assertSame(renderResponse, PortletActionContext.getRenderResponse());
assertSame(renderRequest, PortletActionContext.getRequest());
assertSame(renderResponse, PortletActionContext.getResponse());
}
public void testGetRenderRequestAndResponseInEventPhase() {
context.put(PortletActionConstants.REQUEST, renderRequest);
context.put(PortletActionConstants.RESPONSE, renderResponse);
context.put(PortletActionConstants.PHASE, PortletActionConstants.EVENT_PHASE);
try {
PortletActionContext.getRenderRequest();
fail("Should throw IllegalStateException!");
}
catch(IllegalStateException e) {
assertTrue(true);
}
try {
PortletActionContext.getRenderResponse();
fail("Should throw IllegalStateException!");
}
catch(IllegalStateException e) {
assertTrue(true);
}
}
public void testGetActionRequestAndResponse() {
context.put(PortletActionConstants.REQUEST, actionRequest);
context.put(PortletActionConstants.RESPONSE, actionResponse);
context.put(PortletActionConstants.PHASE, PortletActionConstants.EVENT_PHASE);
assertSame(actionRequest, PortletActionContext.getActionRequest());
assertSame(actionResponse, PortletActionContext.getActionResponse());
assertSame(actionRequest, PortletActionContext.getRequest());
assertSame(actionResponse, PortletActionContext.getResponse());
}
public void testGetActionRequestAndResponseInRenderPhase() {
context.put(PortletActionConstants.REQUEST, actionRequest);
context.put(PortletActionConstants.RESPONSE, actionResponse);
context.put(PortletActionConstants.PHASE, PortletActionConstants.RENDER_PHASE);
try {
PortletActionContext.getActionRequest();
fail("Should throw IllegalStateException!");
}
catch(IllegalStateException e) {
assertTrue(true);
}
try {
PortletActionContext.getActionResponse();
fail("Should throw IllegalStateException!");
}
catch(IllegalStateException e) {
assertTrue(true);
}
}
public void testGetNamespace() {
context.put(PortletActionConstants.PORTLET_NAMESPACE, "testNamespace");
assertEquals("testNamespace", PortletActionContext.getPortletNamespace());
}
public void testGetDefaultActionForMode() {
ActionMapping mapping = new ActionMapping();
context.put(PortletActionConstants.DEFAULT_ACTION_FOR_MODE, mapping);
assertEquals(mapping, PortletActionContext.getDefaultActionForMode());
}
public void tearDown() throws Exception {
ActionContext.setContext(null);
super.tearDown();
}
public static void main(String[] args) {
TestRunner.run(PortletActionContextTest.class);
}
}
@@ -0,0 +1,67 @@
/*
* $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.context;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsTestCase;
import org.easymock.MockControl;
/**
*
* Test for the {@link PreparatorServletTest}
*
*/
public class PreparatorServletTest extends StrutsTestCase {
/**
* Test that the service method stores the request, response and servlet context
* in the {@link com.opensymphony.xwork2.ActionContext}
*/
public void testServiceHttpServletRequestHttpServletResponse() throws Exception {
MockControl mockRequest = MockControl.createNiceControl(HttpServletRequest.class);
MockControl mockResponse = MockControl.createNiceControl(HttpServletResponse.class);
MockControl mockContext = MockControl.createNiceControl(ServletContext.class);
MockControl mockConfig = MockControl.createNiceControl(ServletConfig.class);
HttpServletRequest req = (HttpServletRequest)mockRequest.getMock();
HttpServletResponse res = (HttpServletResponse)mockResponse.getMock();
ServletContext context = (ServletContext)mockContext.getMock();
ServletConfig config = (ServletConfig)mockConfig.getMock();
mockConfig.expectAndDefaultReturn(config.getServletContext(), context);
mockConfig.replay();
PreparatorServlet servlet = new PreparatorServlet();
servlet.init(config);
servlet.service(req, res);
assertSame(req, ServletActionContext.getRequest());
assertSame(res, ServletActionContext.getResponse());
assertSame(context, ServletActionContext.getServletContext());
mockConfig.verify();
}
}
@@ -0,0 +1,46 @@
/*
* $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.context;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import junit.framework.TestCase;
import org.easymock.MockControl;
/**
*/
public class ServletContextHolderListenerTest extends TestCase {
public void testContextInitialized() {
MockControl mockContext = MockControl.createNiceControl(ServletContext.class);
ServletContext context = (ServletContext)mockContext.getMock();
ServletContextEvent event = new ServletContextEvent(context);
ServletContextHolderListener listener = new ServletContextHolderListener();
listener.contextInitialized(event);
assertSame(ServletContextHolderListener.getServletContext(), context);
listener.contextDestroyed(event);
assertNull(ServletContextHolderListener.getServletContext());
}
}
@@ -0,0 +1,305 @@
/*
* $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.dispatcher;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.ListResourceBundle;
import java.util.Locale;
import java.util.Map;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletMode;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.WindowState;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import junit.textui.TestRunner;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.portlet.PortletActionConstants;
import org.apache.struts2.portlet.context.ServletContextHolderListener;
import org.jmock.Mock;
import org.jmock.cglib.MockObjectTestCase;
import org.jmock.core.Constraint;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.ActionProxyFactory;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ValueStackFactory;
/**
* Jsr168DispatcherTest. Insert description.
*
*/
public class Jsr168DispatcherTest extends MockObjectTestCase implements PortletActionConstants {
Jsr168Dispatcher dispatcher = null;
Mock mockConfig = null;
Mock mockCtx = null;
Mock mockRequest = null;
Mock mockSession = null;
Mock mockActionFactory = null;
Mock mockActionProxy = null;
Mock mockAction = null;
Mock mockInvocation = null;
public void setUp() {
dispatcher = new Jsr168Dispatcher();
}
private void initPortletConfig(final Map initParams, final Map attributes) {
mockConfig = mock(PortletConfig.class);
mockCtx = mock(PortletContext.class);
mockConfig.stubs().method(ANYTHING);
setupStub(initParams, mockConfig, "getInitParameter");
mockCtx.stubs().method("getAttributeNames").will(returnValue(Collections.enumeration(attributes.keySet())));
setupStub(attributes, mockCtx, "getAttribute");
mockConfig.stubs().method("getPortletContext").will(returnValue(mockCtx.proxy()));
mockCtx.stubs().method("getInitParameterNames").will(returnValue(Collections.enumeration(initParams.keySet())));
setupStub(initParams, mockCtx, "getInitParameter");
mockConfig.stubs().method("getInitParameterNames").will(returnValue(Collections.enumeration(initParams.keySet())));
setupStub(initParams, mockConfig, "getInitParameter");
mockConfig.stubs().method("getResourceBundle").will(returnValue(new ListResourceBundle() {
protected Object[][] getContents() {
return new String[][]{{"javax.portlet.title", "MyTitle"}};
}
}));
}
private void setupActionFactory(String namespace, String actionName, String result, ValueStack stack) {
if(mockActionFactory == null) {
mockActionFactory = mock(ActionProxyFactory.class);
}
mockAction = mock(Action.class);
mockActionProxy = mock(ActionProxy.class);
mockInvocation = mock(ActionInvocation.class);
mockActionFactory.expects(once()).method("createActionProxy").with(new Constraint[]{eq(namespace), eq(actionName), isA(Map.class)}).will(returnValue(mockActionProxy.proxy()));
mockActionProxy.stubs().method("getAction").will(returnValue(mockAction.proxy()));
mockActionProxy.expects(once()).method("execute").will(returnValue(result));
mockActionProxy.expects(once()).method("getInvocation").will(returnValue(mockInvocation.proxy()));
mockActionProxy.expects(once()).method("setMethod");
mockInvocation.stubs().method("getStack").will(returnValue(stack));
}
public void testRender_ok() {
final Mock mockResponse = mock(RenderResponse.class);
mockResponse.stubs().method(ANYTHING);
final Mock servletContext = mock(ServletContext.class);
servletContext.stubs().method(ANYTHING);
ServletContextEvent event = new ServletContextEvent((ServletContext)servletContext.proxy());
new ServletContextHolderListener().contextInitialized(event);
PortletMode mode = PortletMode.VIEW;
Map requestParams = new HashMap();
requestParams.put(PortletActionConstants.ACTION_PARAM, new String[]{"/view/testAction"});
requestParams.put(EVENT_ACTION, new String[]{"true"});
requestParams.put(PortletActionConstants.MODE_PARAM, new String[]{mode.toString()});
Map sessionMap = new HashMap();
Map initParams = new HashMap();
initParams.put("viewNamespace", "/view");
initParams.put(StrutsConstants.STRUTS_ALWAYS_SELECT_FULL_NAMESPACE, "true");
initPortletConfig(initParams, new HashMap());
initRequest(requestParams, new HashMap(), sessionMap, new HashMap(), PortletMode.VIEW, WindowState.NORMAL, false, null);
setupActionFactory("/view", "testAction", "success", ValueStackFactory.getFactory().createValueStack());
mockInvocation.expects(once()).method("getStack").will(
returnValue(null));
//mockSession.expects(once()).method("setAttribute").with(new Constraint[]{eq(PortletActionConstants.LAST_MODE), eq(PortletMode.VIEW)});
try {
dispatcher
.setActionProxyFactory((ActionProxyFactory) mockActionFactory
.proxy());
dispatcher.init((PortletConfig) mockConfig.proxy());
dispatcher.render((RenderRequest) mockRequest.proxy(),
(RenderResponse) mockResponse.proxy());
} catch (Exception e) {
e.printStackTrace();
fail("Error occured");
}
}
public void testProcessAction_ok() {
final Mock mockResponse = mock(ActionResponse.class);
PortletMode mode = PortletMode.VIEW;
Map initParams = new HashMap();
initParams.put("viewNamespace", "/view");
Map requestParams = new HashMap();
requestParams.put(PortletActionConstants.ACTION_PARAM, new String[]{"/view/testAction"});
requestParams.put(PortletActionConstants.MODE_PARAM, new String[]{mode.toString()});
initParams.put(StrutsConstants.STRUTS_ALWAYS_SELECT_FULL_NAMESPACE, "true");
initPortletConfig(initParams, new HashMap());
initRequest(requestParams, new HashMap(), new HashMap(), new HashMap(), PortletMode.VIEW, WindowState.NORMAL, true, null);
setupActionFactory("/view", "testAction", "success", ValueStackFactory.getFactory().createValueStack());
Constraint[] paramConstraints = new Constraint[] {
eq(PortletActionConstants.EVENT_ACTION), same(mockActionProxy.proxy()) };
mockSession.expects(once()).method("setAttribute").with(
paramConstraints);
mockResponse.expects(once()).method("setRenderParameter").with(
new Constraint[] { eq(PortletActionConstants.EVENT_ACTION),
eq("true") });
//mockSession.expects(once()).method("setAttribute").with(new Constraint[]{eq(PortletActionConstants.LAST_MODE), eq(PortletMode.VIEW)});
try {
dispatcher
.setActionProxyFactory((ActionProxyFactory) mockActionFactory
.proxy());
dispatcher.init((PortletConfig) mockConfig.proxy());
dispatcher.processAction((ActionRequest) mockRequest.proxy(),
(ActionResponse) mockResponse.proxy());
} catch (Exception e) {
e.printStackTrace();
fail("Error occured");
}
}
/**
* Initialize the mock request (and as a result, the mock session)
* @param requestParams The request parameters
* @param requestAttributes The request attributes
* @param sessionParams The session attributes
* @param renderParams The render parameters. Will only be set if <code>isEvent</code> is <code>true</code>
* @param mode The portlet mode
* @param state The portlet window state
* @param isEvent <code>true</code> when the request is an ActionRequest.
* @param locale The locale. If <code>null</code>, the request will return <code>Locale.getDefault()</code>
*/
private void initRequest(Map requestParams, Map requestAttributes, Map sessionParams, Map renderParams, PortletMode mode, WindowState state, boolean isEvent, Locale locale) {
mockRequest = isEvent ? mock(ActionRequest.class) : mock(RenderRequest.class);
mockSession = mock(PortletSession.class);
mockSession.stubs().method(ANYTHING);
mockRequest.stubs().method(ANYTHING);
setupStub(sessionParams, mockSession, "getAttribute");
mockSession.stubs().method("getAttributeNames").will(returnValue(Collections.enumeration(sessionParams.keySet())));
setupParamStub(requestParams, mockRequest, "getParameter");
setupStub(requestAttributes, mockRequest, "getAttribute");
mockRequest.stubs().method("getAttributeNames").will(returnValue(Collections.enumeration(requestAttributes.keySet())));
mockRequest.stubs().method("getParameterMap").will(returnValue(requestParams));
mockRequest.stubs().method("getParameterNames").will(returnValue(Collections.enumeration(requestParams.keySet())));
mockRequest.stubs().method("getPortletSession").will(returnValue(mockSession.proxy()));
if(locale != null) {
mockRequest.stubs().method("getLocale").will(returnValue(locale));
}
else {
mockRequest.stubs().method("getLocale").will(returnValue(Locale.getDefault()));
}
mockRequest.stubs().method("getPortletMode").will(returnValue(mode));
mockRequest.stubs().method("getWindowState").will(returnValue(state));
}
/**
* @param requestParams
* @param mockRequest2
* @param string
*/
private void setupParamStub(Map requestParams, Mock mockRequest, String method) {
Map newMap = new HashMap();
Iterator it = requestParams.keySet().iterator();
while(it.hasNext()) {
Object key = it.next();
String[] val = (String[])requestParams.get(key);
newMap.put(key, val[0]);
}
setupStub(newMap, mockRequest, method);
}
/**
* Set up stubs for the mock.
* @param map The map containing the <code>key</code> and <code>values</code>. The key is the
* expected parameter to <code>method</code>, and value is the value that should be returned from
* the stub.
* @param mock The mock to initialize.
* @param method The name of the method to stub.
*/
private void setupStub(Map map, Mock mock, String method) {
Iterator it = map.keySet().iterator();
while(it.hasNext()) {
Object key = it.next();
Object val = map.get(key);
mock.stubs().method(method).with(eq(key)).will(returnValue(val));
}
}
public void testModeChangeUsingPortletWidgets() {
final Mock mockResponse = mock(RenderResponse.class);
mockResponse.stubs().method(ANYTHING);
PortletMode mode = PortletMode.EDIT;
Map requestParams = new HashMap();
requestParams.put(PortletActionConstants.ACTION_PARAM, new String[]{"/view/testAction"});
requestParams.put(EVENT_ACTION, new String[]{"false"});
requestParams.put(PortletActionConstants.MODE_PARAM, new String[]{PortletMode.VIEW.toString()});
Map sessionMap = new HashMap();
Map initParams = new HashMap();
initParams.put("viewNamespace", "/view");
initParams.put("editNamespace", "/edit");
initPortletConfig(initParams, new HashMap());
initRequest(requestParams, new HashMap(), sessionMap, new HashMap(), mode, WindowState.NORMAL, false, null);
setupActionFactory("/edit", "default", "success", ValueStackFactory.getFactory().createValueStack());
mockInvocation.expects(once()).method("getStack").will(
returnValue(null));
//mockSession.expects(once()).method("setAttribute").with(new Constraint[]{eq(PortletActionConstants.LAST_MODE), eq(PortletMode.VIEW)});
try {
dispatcher
.setActionProxyFactory((ActionProxyFactory) mockActionFactory
.proxy());
dispatcher.init((PortletConfig) mockConfig.proxy());
dispatcher.render((RenderRequest) mockRequest.proxy(),
(RenderResponse) mockResponse.proxy());
} catch (Exception e) {
e.printStackTrace();
fail("Error occured");
}
}
public static void main(String[] args) {
TestRunner.run(Jsr168DispatcherTest.class);
}
}
@@ -0,0 +1,248 @@
/*
* $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.result;
import java.util.HashMap;
import java.util.Map;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletMode;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import junit.textui.TestRunner;
import org.apache.struts2.portlet.PortletActionConstants;
import org.jmock.Mock;
import org.jmock.cglib.MockObjectTestCase;
import org.jmock.core.Constraint;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
/**
* PortletResultTest. Insert description.
*
*/
public class PortletResultTest extends MockObjectTestCase {
Mock mockInvocation = null;
Mock mockConfig = null;
Mock mockCtx = null;
public void setUp() throws Exception {
super.setUp();
mockInvocation = mock(ActionInvocation.class);
mockConfig = mock(PortletConfig.class);
mockCtx = mock(PortletContext.class);
mockConfig.stubs().method(ANYTHING);
mockConfig.stubs().method("getPortletContext").will(returnValue(mockCtx.proxy()));
Map paramMap = new HashMap();
Map sessionMap = new HashMap();
Map context = new HashMap();
context.put(ActionContext.SESSION, sessionMap);
context.put(ActionContext.PARAMETERS, paramMap);
context.put(PortletActionConstants.PORTLET_CONFIG, mockConfig.proxy());
ActionContext.setContext(new ActionContext(context));
mockInvocation.stubs().method("getInvocationContext").will(returnValue(ActionContext.getContext()));
}
public void testDoExecute_render() {
Mock mockRequest = mock(RenderRequest.class);
Mock mockResponse = mock(RenderResponse.class);
Mock mockRd = mock(PortletRequestDispatcher.class);
Mock mockPrep = mock(PortletRequestDispatcher.class);
RenderRequest req = (RenderRequest)mockRequest.proxy();
RenderResponse res = (RenderResponse)mockResponse.proxy();
PortletRequestDispatcher rd = (PortletRequestDispatcher)mockRd.proxy();
PortletConfig cfg = (PortletConfig)mockConfig.proxy();
PortletContext ctx = (PortletContext)mockCtx.proxy();
ActionInvocation inv = (ActionInvocation)mockInvocation.proxy();
Constraint[] params = new Constraint[]{same(req), same(res)};
mockRd.expects(once()).method("include").with(params);
mockPrep.expects(once()).method("include").with(params);
mockCtx.expects(once()).method("getRequestDispatcher").with(eq("/WEB-INF/pages/testPage.jsp")).will(returnValue(rd));
mockCtx.expects(once()).method("getNamedDispatcher").with(eq("preparator")).will(returnValue(mockPrep.proxy()));
mockResponse.expects(once()).method("setContentType").with(eq("text/html"));
mockConfig.expects(once()).method("getPortletContext").will(returnValue(ctx));
mockRequest.stubs().method("getPortletMode").will(returnValue(PortletMode.VIEW));
ActionContext ctxMap = ActionContext.getContext();
ctxMap.put(PortletActionConstants.RESPONSE, res);
ctxMap.put(PortletActionConstants.REQUEST, req);
ctxMap.put(PortletActionConstants.PORTLET_CONFIG, cfg);
ctxMap.put(PortletActionConstants.PHASE, PortletActionConstants.RENDER_PHASE);
PortletResult result = new PortletResult();
try {
result.doExecute("/WEB-INF/pages/testPage.jsp", inv);
}
catch(Exception e) {
e.printStackTrace();
fail("Error occured!");
}
}
public void testDoExecute_event_locationIsAction() {
Mock mockRequest = mock(ActionRequest.class);
Mock mockResponse = mock(ActionResponse.class);
Constraint[] params = new Constraint[]{eq(PortletActionConstants.ACTION_PARAM), eq("testView")};
mockResponse.expects(once()).method("setRenderParameter").with(params);
params = new Constraint[]{eq(PortletActionConstants.MODE_PARAM), eq(PortletMode.VIEW.toString())};
mockResponse.expects(once()).method("setRenderParameter").with(params);
mockRequest.stubs().method("getPortletMode").will(returnValue(PortletMode.VIEW));
ActionContext ctx = ActionContext.getContext();
ctx.put(PortletActionConstants.REQUEST, mockRequest.proxy());
ctx.put(PortletActionConstants.RESPONSE, mockResponse.proxy());
ctx.put(PortletActionConstants.PHASE, PortletActionConstants.EVENT_PHASE);
PortletResult result = new PortletResult();
try {
result.doExecute("testView.action", (ActionInvocation)mockInvocation.proxy());
}
catch(Exception e) {
e.printStackTrace();
fail("Error occured!");
}
}
public void testDoExecute_event_locationIsJsp() {
Mock mockRequest = mock(ActionRequest.class);
Mock mockResponse = mock(ActionResponse.class);
Constraint[] params = new Constraint[]{eq(PortletActionConstants.ACTION_PARAM), eq("renderDirect")};
mockResponse.expects(once()).method("setRenderParameter").with(params);
params = new Constraint[]{eq("location"), eq("/WEB-INF/pages/testJsp.jsp")};
mockResponse.expects(once()).method("setRenderParameter").with(params);
params = new Constraint[]{eq(PortletActionConstants.MODE_PARAM), eq(PortletMode.VIEW.toString())};
mockResponse.expects(once()).method("setRenderParameter").with(params);
mockRequest.stubs().method("getPortletMode").will(returnValue(PortletMode.VIEW));
ActionContext ctx = ActionContext.getContext();
ctx.put(PortletActionConstants.REQUEST, mockRequest.proxy());
ctx.put(PortletActionConstants.RESPONSE, mockResponse.proxy());
ctx.put(PortletActionConstants.PHASE, PortletActionConstants.EVENT_PHASE);
PortletResult result = new PortletResult();
try {
result.doExecute("/WEB-INF/pages/testJsp.jsp", (ActionInvocation)mockInvocation.proxy());
}
catch(Exception e) {
e.printStackTrace();
fail("Error occured!");
}
}
public void testDoExecute_event_locationHasQueryParams() {
Mock mockRequest = mock(ActionRequest.class);
Mock mockResponse = mock(ActionResponse.class);
Constraint[] params = new Constraint[]{eq(PortletActionConstants.ACTION_PARAM), eq("testView")};
mockResponse.expects(once()).method("setRenderParameter").with(params);
params = new Constraint[]{eq("testParam1"), eq("testValue1")};
mockResponse.expects(once()).method("setRenderParameter").with(params);
params = new Constraint[]{eq("testParam2"), eq("testValue2")};
mockResponse.expects(once()).method("setRenderParameter").with(params);
params = new Constraint[]{eq(PortletActionConstants.MODE_PARAM), eq(PortletMode.VIEW.toString())};
mockResponse.expects(once()).method("setRenderParameter").with(params);
mockRequest.stubs().method("getPortletMode").will(returnValue(PortletMode.VIEW));
ActionContext ctx = ActionContext.getContext();
ctx.put(PortletActionConstants.REQUEST, mockRequest.proxy());
ctx.put(PortletActionConstants.RESPONSE, mockResponse.proxy());
ctx.put(PortletActionConstants.PHASE, PortletActionConstants.EVENT_PHASE);
PortletResult result = new PortletResult();
try {
result.doExecute("testView.action?testParam1=testValue1&testParam2=testValue2", (ActionInvocation)mockInvocation.proxy());
}
catch(Exception e) {
e.printStackTrace();
fail("Error occured!");
}
}
public void testTitleAndContentType() throws Exception {
Mock mockRequest = mock(RenderRequest.class);
Mock mockResponse = mock(RenderResponse.class);
Mock mockRd = mock(PortletRequestDispatcher.class);
Mock mockPrep = mock(PortletRequestDispatcher.class);
RenderRequest req = (RenderRequest)mockRequest.proxy();
RenderResponse res = (RenderResponse)mockResponse.proxy();
PortletRequestDispatcher rd = (PortletRequestDispatcher)mockRd.proxy();
PortletConfig cfg = (PortletConfig)mockConfig.proxy();
PortletContext ctx = (PortletContext)mockCtx.proxy();
Constraint[] params = new Constraint[]{same(req), same(res)};
mockRd.expects(once()).method("include").with(params);
mockPrep.expects(once()).method("include").with(params);
mockCtx.expects(once()).method("getRequestDispatcher").with(eq("/WEB-INF/pages/testPage.jsp")).will(returnValue(rd));
mockCtx.expects(once()).method("getNamedDispatcher").with(eq("preparator")).will(returnValue(mockPrep.proxy()));
mockConfig.expects(once()).method("getPortletContext").will(returnValue(ctx));
mockRequest.stubs().method("getPortletMode").will(returnValue(PortletMode.VIEW));
ActionContext ctxMap = ActionContext.getContext();
ctxMap.put(PortletActionConstants.RESPONSE, res);
ctxMap.put(PortletActionConstants.REQUEST, req);
ctxMap.put(PortletActionConstants.PORTLET_CONFIG, cfg);
ctxMap.put(PortletActionConstants.PHASE, PortletActionConstants.RENDER_PHASE);
mockResponse.expects(atLeastOnce()).method("setTitle").with(eq("testTitle"));
mockResponse.expects(atLeastOnce()).method("setContentType").with(eq("testContentType"));
PortletResult result = new PortletResult();
result.setTitle("testTitle");
result.setContentType("testContentType");
result.doExecute("/WEB-INF/pages/testPage.jsp", (ActionInvocation)mockInvocation.proxy());
}
public void tearDown() throws Exception {
super.tearDown();
ActionContext.setContext(null);
}
public static void main(String[] args) {
TestRunner.run(PortletResultTest.class);
}
}
@@ -0,0 +1,159 @@
/*
* $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.util;
import java.util.HashMap;
import java.util.Map;
import javax.portlet.PortletMode;
import javax.portlet.PortletURL;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.WindowState;
import junit.framework.TestCase;
import org.apache.struts2.portlet.context.PortletActionContext;
import org.easymock.MockControl;
import com.opensymphony.xwork2.ActionContext;
/**
*/
public class PortletUrlHelperTest extends TestCase {
RenderResponse renderResponse;
RenderRequest renderRequest;
PortletURL url;
MockControl renderResponseControl;
MockControl renderRequestControl;
MockControl portletUrlControl;
public void setUp() throws Exception {
super.setUp();
renderRequestControl = MockControl.createControl(RenderRequest.class);
renderResponseControl = MockControl.createControl(RenderResponse.class);
portletUrlControl = MockControl.createControl(PortletURL.class);
renderRequest = (RenderRequest) renderRequestControl.getMock();
renderResponse = (RenderResponse) renderResponseControl.getMock();
url = (PortletURL) portletUrlControl.getMock();
renderRequestControl.expectAndDefaultReturn(renderRequest
.getPortletMode(), PortletMode.VIEW);
renderRequestControl.expectAndDefaultReturn(renderRequest
.getWindowState(), WindowState.NORMAL);
Map modeNamespaceMap = new HashMap();
modeNamespaceMap.put("view", "/view");
modeNamespaceMap.put("edit", "/edit");
modeNamespaceMap.put("help", "/help");
Map context = new HashMap();
context.put(PortletActionContext.REQUEST, renderRequest);
context.put(PortletActionContext.RESPONSE, renderResponse);
context.put(PortletActionContext.PHASE,
PortletActionContext.RENDER_PHASE);
context.put(PortletActionContext.MODE_NAMESPACE_MAP, modeNamespaceMap);
ActionContext.setContext(new ActionContext(context));
}
public void testCreateRenderUrlWithNoModeOrState() throws Exception {
renderResponseControl.expectAndReturn(renderResponse.createRenderURL(),
url);
url.setPortletMode(PortletMode.VIEW);
url.setWindowState(WindowState.NORMAL);
url.setParameters(null);
portletUrlControl.setMatcher(MockControl.ALWAYS_MATCHER);
renderRequestControl.replay();
renderResponseControl.replay();
portletUrlControl.replay();
PortletUrlHelper.buildUrl("testAction", null,
new HashMap(), null, null, null);
portletUrlControl.verify();
renderRequestControl.verify();
renderResponseControl.verify();
}
public void testCreateRenderUrlWithDifferentPortletMode() throws Exception {
renderResponseControl.expectAndReturn(renderResponse.createRenderURL(),
url);
url.setPortletMode(PortletMode.EDIT);
url.setWindowState(WindowState.NORMAL);
url.setParameters(null);
portletUrlControl.setMatcher(MockControl.ALWAYS_MATCHER);
renderRequestControl.replay();
renderResponseControl.replay();
portletUrlControl.replay();
PortletUrlHelper.buildUrl("testAction", null,
new HashMap(), null, "edit", null);
portletUrlControl.verify();
renderRequestControl.verify();
renderResponseControl.verify();
}
public void testCreateRenderUrlWithDifferentWindowState() throws Exception {
renderResponseControl.expectAndReturn(renderResponse.createRenderURL(),
url);
url.setPortletMode(PortletMode.VIEW);
url.setWindowState(WindowState.MAXIMIZED);
url.setParameters(null);
portletUrlControl.setMatcher(MockControl.ALWAYS_MATCHER);
renderRequestControl.replay();
renderResponseControl.replay();
portletUrlControl.replay();
PortletUrlHelper.buildUrl("testAction", null,
new HashMap(), null, null, "maximized");
portletUrlControl.verify();
renderRequestControl.verify();
renderResponseControl.verify();
}
public void testCreateActionUrl() throws Exception {
renderResponseControl.expectAndReturn(renderResponse.createActionURL(),
url);
url.setPortletMode(PortletMode.VIEW);
url.setWindowState(WindowState.NORMAL);
url.setParameters(null);
portletUrlControl.setMatcher(MockControl.ALWAYS_MATCHER);
renderRequestControl.replay();
renderResponseControl.replay();
portletUrlControl.replay();
PortletUrlHelper.buildUrl("testAction", null,
new HashMap(), "action", null, null);
portletUrlControl.verify();
renderRequestControl.verify();
renderResponseControl.verify();
}
}
@@ -0,0 +1,363 @@
/*
* $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.views.jsp;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.portlet.PortletMode;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.PortletURL;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.WindowState;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.PageContext;
import junit.textui.TestRunner;
import org.apache.struts2.dispatcher.Dispatcher;
import org.apache.struts2.portlet.PortletActionConstants;
import org.apache.struts2.portlet.util.PortletUrlHelper;
import org.jmock.Mock;
import org.jmock.cglib.MockObjectTestCase;
import org.jmock.core.Constraint;
import com.mockobjects.servlet.MockJspWriter;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ValueStackFactory;
/**
*/
public class PortletUrlTagTest extends MockObjectTestCase {
URLTag tag = new URLTag();
Mock mockHttpReq = null;
Mock mockHttpRes = null;
Mock mockPortletReq = null;
Mock mockPortletRes = null;
Mock mockPageCtx = null;
Mock mockPortletUrl = null;
MockJspWriter mockJspWriter = null;
ValueStack stack = null;
public static void main(String[] args) {
TestRunner.run(PortletUrlTagTest.class);
}
public void setUp() throws Exception {
super.setUp();
Dispatcher du = new Dispatcher(null, new HashMap());
du.init();
Dispatcher.setInstance(du);
mockPortletApiAvailable();
stack = ValueStackFactory.getFactory().createValueStack();
mockHttpReq = mock(HttpServletRequest.class);
mockHttpRes = mock(HttpServletResponse.class);
mockPortletReq = mock(RenderRequest.class);
mockPortletRes = mock(RenderResponse.class);
mockPageCtx = mock(PageContext.class);
mockPortletUrl = mock(PortletURL.class);
mockJspWriter = new MockJspWriter();
mockPageCtx.stubs().method("getRequest").will(
returnValue((HttpServletRequest) mockHttpReq.proxy()));
mockPageCtx.stubs().method("getResponse").will(
returnValue((HttpServletResponse) mockHttpRes.proxy()));
mockPageCtx.stubs().method("getOut").will(returnValue(mockJspWriter));
mockHttpReq.stubs().method("getScheme").will(returnValue("http"));
mockHttpReq.stubs().method("getAttribute").with(
eq("struts.valueStack")).will(returnValue(stack));
mockHttpReq.stubs().method("getAttribute").with(
eq("javax.portlet.response")).will(
returnValue((PortletResponse) mockPortletRes.proxy()));
mockHttpReq.stubs().method("getAttribute").with(
eq("javax.portlet.request")).will(
returnValue((PortletRequest) mockPortletReq.proxy()));
mockPortletReq.stubs().method("getPortletMode").will(returnValue(PortletMode.VIEW));
mockPortletReq.stubs().method("getWindowState").will(returnValue(WindowState.NORMAL));
mockPortletReq.stubs().method("getContextPath").will(returnValue("/contextPath"));
tag.setPageContext((PageContext) mockPageCtx.proxy());
Map modeMap = new HashMap();
modeMap.put(PortletMode.VIEW, "/view");
modeMap.put(PortletMode.HELP, "/help");
modeMap.put(PortletMode.EDIT, "/edit");
Map sessionMap = new HashMap();
Map contextMap = new HashMap();
contextMap.put(ActionContext.SESSION, sessionMap);
contextMap.put(PortletActionConstants.REQUEST, mockPortletReq.proxy());
contextMap.put(PortletActionConstants.RESPONSE, mockPortletRes.proxy());
contextMap.put(PortletActionConstants.PHASE, PortletActionConstants.RENDER_PHASE);
contextMap.put(PortletActionConstants.MODE_NAMESPACE_MAP, modeMap);
ActionContext ctx = new ActionContext(contextMap);
ctx.setValueStack(stack);
ActionContext.setContext(ctx);
}
/**
*
*/
private void mockPortletApiAvailable() {
try {
Field field = Dispatcher.class.getDeclaredField("portletSupportActive");
field.setAccessible(true);
field.set(null, Boolean.TRUE);
}
catch(Exception e) {
}
}
public void testEnsureParamsAreStringArrays() {
Map params = new HashMap();
params.put("param1", "Test1");
params.put("param2", new String[] { "Test2" });
Map result = PortletUrlHelper.ensureParamsAreStringArrays(params);
assertEquals(2, result.size());
assertTrue(result.get("param1") instanceof String[]);
}
public void testSetWindowState() throws Exception {
PortletMode mode = PortletMode.VIEW;
mockHttpReq.stubs().method("getQueryString").will(returnValue(""));
mockPortletRes.expects(once()).method("createRenderURL").will(
returnValue((PortletURL) mockPortletUrl.proxy()));
Map paramMap = new HashMap();
paramMap.put(PortletActionConstants.ACTION_PARAM, new String[]{"/view/testAction"});
paramMap.put(PortletActionConstants.MODE_PARAM, new String[]{mode.toString()});
mockPortletUrl.expects(once()).method("setParameters").with(new ParamMapConstraint(paramMap));
mockPortletUrl.expects(once()).method("setWindowState").with(eq(WindowState.MAXIMIZED));
mockPortletUrl.expects(once()).method("setPortletMode").with(eq(PortletMode.VIEW));
tag.setAction("testAction");
tag.setWindowState("maximized");
tag.doStartTag();
tag.doEndTag();
}
public void testSetPortletMode() throws Exception {
PortletMode mode = PortletMode.HELP;
mockHttpReq.stubs().method("getQueryString").will(returnValue(""));
mockPortletRes.expects(once()).method("createRenderURL").will(
returnValue((PortletURL) mockPortletUrl.proxy()));
Map paramMap = new HashMap();
paramMap.put(PortletActionConstants.ACTION_PARAM, new String[]{"/help/testAction"});
paramMap.put(PortletActionConstants.MODE_PARAM, new String[]{mode.toString()});
mockPortletUrl.expects(once()).method("setParameters").with(new ParamMapConstraint(paramMap));
mockPortletUrl.expects(once()).method("setPortletMode").with(eq(PortletMode.HELP));
mockPortletUrl.expects(once()).method("setWindowState").with(eq(WindowState.NORMAL));
tag.setAction("testAction");
tag.setPortletMode("help");
tag.doStartTag();
tag.doEndTag();
}
public void testUrlWithQueryParams() throws Exception {
PortletMode mode = PortletMode.VIEW;
mockHttpReq.stubs().method("getQueryString").will(returnValue(""));
mockPortletRes.expects(once()).method("createRenderURL").will(
returnValue((PortletURL) mockPortletUrl.proxy()));
Map paramMap = new HashMap();
paramMap.put(PortletActionConstants.ACTION_PARAM, new String[]{"/view/testAction"});
paramMap.put("testParam1", new String[]{"testValue1"});
paramMap.put(PortletActionConstants.MODE_PARAM, new String[]{mode.toString()});
mockPortletUrl.expects(once()).method("setParameters").with(new ParamMapConstraint(paramMap));
mockPortletUrl.expects(once()).method("setPortletMode").with(eq(PortletMode.VIEW));
mockPortletUrl.expects(once()).method("setWindowState").with(eq(WindowState.NORMAL));
tag.setAction("testAction?testParam1=testValue1");
tag.doStartTag();
tag.doEndTag();
}
public void testActionUrl() throws Exception {
PortletMode mode = PortletMode.VIEW;
mockHttpReq.stubs().method("getQueryString").will(returnValue(""));
mockPortletRes.expects(once()).method("createActionURL").will(
returnValue((PortletURL) mockPortletUrl.proxy()));
Map paramMap = new HashMap();
paramMap.put(PortletActionConstants.ACTION_PARAM, new String[]{"/view/testAction"});
paramMap.put(PortletActionConstants.MODE_PARAM, new String[]{mode.toString()});
mockPortletUrl.expects(once()).method("setParameters").with(new ParamMapConstraint(paramMap));
mockPortletUrl.expects(once()).method("setPortletMode").with(eq(PortletMode.VIEW));
mockPortletUrl.expects(once()).method("setWindowState").with(eq(WindowState.NORMAL));
tag.setAction("testAction");
tag.setPortletUrlType("action");
tag.doStartTag();
tag.doEndTag();
}
public void testResourceUrl() throws Exception {
mockHttpReq.stubs().method("getQueryString").will(returnValue(""));
mockPortletRes.expects(once()).method("encodeURL").will(returnValue("/contextPath/image.gif"));
mockJspWriter.setExpectedData("/contextPath/image.gif");
tag.setValue("image.gif");
tag.doStartTag();
tag.doEndTag();
mockJspWriter.verify();
}
public void testResourceUrlWithNestedParam() throws Exception {
mockHttpReq.stubs().method("getQueryString").will(returnValue(""));
mockPortletRes.expects(once()).method("encodeURL").with(eq("/contextPath/image.gif?testParam1=testValue1")).will(returnValue("/contextPath/image.gif?testParam1=testValue1"));
mockJspWriter.setExpectedData("/contextPath/image.gif?testParam1=testValue1");
ParamTag paramTag = new ParamTag();
paramTag.setPageContext((PageContext)mockPageCtx.proxy());
paramTag.setParent(tag);
paramTag.setName("testParam1");
paramTag.setValue("'testValue1'");
tag.setValue("image.gif");
tag.doStartTag();
paramTag.doStartTag();
paramTag.doEndTag();
tag.doEndTag();
mockJspWriter.verify();
}
public void testResourceUrlWithTwoNestedParam() throws Exception {
mockHttpReq.stubs().method("getQueryString").will(returnValue(""));
mockPortletRes.expects(once()).method("encodeURL").with(eq("/contextPath/image.gif?testParam1=testValue1&testParam2=testValue2")).will(returnValue("/contextPath/image.gif?testParam1=testValue1&testParam2=testValue2"));
mockJspWriter.setExpectedData("/contextPath/image.gif?testParam1=testValue1&testParam2=testValue2");
ParamTag paramTag = new ParamTag();
paramTag.setPageContext((PageContext)mockPageCtx.proxy());
paramTag.setParent(tag);
paramTag.setName("testParam1");
paramTag.setValue("'testValue1'");
ParamTag paramTag2 = new ParamTag();
paramTag2.setPageContext((PageContext)mockPageCtx.proxy());
paramTag2.setParent(tag);
paramTag2.setName("testParam2");
paramTag2.setValue("'testValue2'");
tag.setValue("image.gif");
tag.doStartTag();
paramTag.doStartTag();
paramTag.doEndTag();
paramTag2.doStartTag();
paramTag2.doEndTag();
tag.doEndTag();
mockJspWriter.verify();
}
private static class ParamMapConstraint implements Constraint {
private Map myExpectedMap = null;
private Map myActualMap = null;
public ParamMapConstraint(Map expectedMap) {
if(expectedMap == null) {
throw new IllegalArgumentException("Use an isNull constraint instead!");
}
myExpectedMap = expectedMap;
}
/* (non-Javadoc)
* @see org.jmock.core.Constraint#eval(java.lang.Object)
*/
public boolean eval(Object val) {
myActualMap = (Map)val;
boolean result = false;
if(val != null) {
if(myExpectedMap.size() == myActualMap.size()) {
Iterator keys = myExpectedMap.keySet().iterator();
boolean allSame = true;
while(keys.hasNext()) {
Object key = keys.next();
if(!myActualMap.containsKey(key)) {
allSame = false;
break;
}
else {
String[] expected = (String[])myExpectedMap.get(key);
String[] actual = (String[])myActualMap.get(key);
if(!Arrays.equals(expected, actual)) {
allSame = false;
break;
}
}
}
result = allSame;
}
}
return result;
}
/* (non-Javadoc)
* @see org.jmock.core.SelfDescribing#describeTo(java.lang.StringBuffer)
*/
public StringBuffer describeTo(StringBuffer sb) {
return sb.append(myExpectedMap);
}
}
}