diff --git a/apps/portlet/pom.xml b/apps/portlet/pom.xml index ead3d6275..695fbb346 100644 --- a/apps/portlet/pom.xml +++ b/apps/portlet/pom.xml @@ -34,7 +34,7 @@ org.apache.pluto maven-pluto-plugin - 1.1.1 + 1.1.3 generate-resources @@ -66,6 +66,11 @@ struts2-core ${pom.version} + + org.apache.struts + struts2-portlet-plugin + ${pom.version} + velocity velocity diff --git a/core/pom.xml b/core/pom.xml index 7db01f1ac..62bbf3f9a 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -337,21 +337,6 @@ true - - - portlet-api - portlet-api - 1.0 - true - - - - org.apache.pluto - pluto - 1.0.1-rc4 - true - - org.springframework @@ -387,12 +372,6 @@ jdk15 - - jmock - jmock - 1.0.1 - test - org.easymock easymock @@ -412,13 +391,6 @@ - - jmock - jmock-cglib - 1.0.1 - test - - mockobjects mockobjects-core @@ -454,6 +426,13 @@ test + + jmock + jmock + 1.0.1 + test + + log4j log4j diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java index 075ef8a1d..7fc6d34b2 100644 --- a/core/src/main/java/org/apache/struts2/StrutsConstants.java +++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java @@ -55,6 +55,8 @@ public final class StrutsConstants { /** The default includeParams method to generate Struts URLs */ public static final String STRUTS_URL_INCLUDEPARAMS = "struts.url.includeParams"; + public static final String STRUTS_URL_RENDERER = "struts.urlRenderer"; + /** The com.opensymphony.xwork2.ObjectFactory implementation class */ public static final String STRUTS_OBJECTFACTORY = "struts.objectFactory"; diff --git a/core/src/main/java/org/apache/struts2/components/Form.java b/core/src/main/java/org/apache/struts2/components/Form.java index b393cd90d..a99ce22ba 100644 --- a/core/src/main/java/org/apache/struts2/components/Form.java +++ b/core/src/main/java/org/apache/struts2/components/Form.java @@ -34,8 +34,8 @@ import org.apache.struts2.views.annotations.StrutsTagAttribute; import org.apache.struts2.StrutsConstants; import org.apache.struts2.dispatcher.Dispatcher; import org.apache.struts2.dispatcher.mapper.ActionMapping; -import org.apache.struts2.portlet.context.PortletActionContext; -import org.apache.struts2.portlet.util.PortletUrlHelper; +//import org.apache.struts2.portlet.context.PortletActionContext; +//import org.apache.struts2.portlet.util.PortletUrlHelper; import org.apache.struts2.views.util.UrlHelper; import com.opensymphony.xwork2.ActionContext; @@ -115,6 +115,7 @@ public class Form extends ClosingUIBean { protected boolean enableDynamicMethodInvocation = true; protected Configuration configuration; protected ObjectFactory objectFactory; + protected UrlRenderer urlRenderer; public Form(ValueStack stack, HttpServletRequest request, HttpServletResponse response) { super(stack, request, response); @@ -146,6 +147,11 @@ public class Form extends ClosingUIBean { public void setObjectFactory(ObjectFactory objectFactory) { this.objectFactory = objectFactory; } + + @Inject + public void setUrlRenderer(UrlRenderer urlRenderer) { + this.urlRenderer = urlRenderer; + } /* @@ -227,13 +233,7 @@ public class Form extends ClosingUIBean { if (id != null) { addParameter("id", escape(id)); } - if (Dispatcher.getInstance().isPortletSupportActive() && PortletActionContext.isPortletRequest()) { - evaluateExtraParamsPortletRequest(namespace, action); - } else { - String namespace = determineNamespace(this.namespace, getStack(), - request); - evaluateExtraParamsServletRequest(action, namespace, isAjax); - } + urlRenderer.renderFormUrl(this); } /** @@ -241,96 +241,9 @@ public class Form extends ClosingUIBean { * @param namespace * @param action */ - private void evaluateExtraParamsServletRequest(String action, String namespace, boolean isAjax) { - if (action == null) { - // no action supplied? ok, then default to the current request (action or general URL) - ActionInvocation ai = (ActionInvocation) getStack().getContext().get(ActionContext.ACTION_INVOCATION); - if (ai != null) { - action = ai.getProxy().getActionName(); - namespace = ai.getProxy().getNamespace(); - } else { - // hmm, ok, we need to just assume the current URL cut down - String uri = request.getRequestURI(); - action = uri.substring(uri.lastIndexOf('/')); - } - } - String actionMethod = ""; - // FIXME: our implementation is flawed - the only concept of ! should be in DefaultActionMapper - // handle "name!method" convention. - if (enableDynamicMethodInvocation) { - if (action.indexOf("!") != -1) { - int endIdx = action.lastIndexOf("!"); - actionMethod = action.substring(endIdx + 1, action.length()); - action = action.substring(0, endIdx); - } - } - final ActionConfig actionConfig = configuration.getRuntimeConfiguration().getActionConfig(namespace, action); - String actionName = action; - if (actionConfig != null) { - - ActionMapping mapping = new ActionMapping(action, namespace, actionMethod, parameters); - String result = UrlHelper.buildUrl(actionMapper.getUriFromActionMapping(mapping), request, response, null); - addParameter("action", result); - - // let's try to get the actual action class and name - // this can be used for getting the list of validators - addParameter("actionName", actionName); - try { - Class clazz = objectFactory.getClassInstance(actionConfig.getClassName()); - addParameter("actionClass", clazz); - } catch (ClassNotFoundException e) { - // this is OK, we'll just move on - } - - addParameter("namespace", namespace); - - // if the name isn't specified, use the action name - if (name == null) { - addParameter("name", action); - } - - // if the id isn't specified, use the action name - if (id == null) { - addParameter("id", action); - } - } else if (action != null) { - // Since we can't find an action alias in the configuration, we just assume - // the action attribute supplied is the path to be used as the uri this - // form is submitting to. - - String result = UrlHelper.buildUrl(action, request, response, null); - addParameter("action", result); - - // namespace: cut out anything between the start and the last / - int slash = result.lastIndexOf('/'); - if (slash != -1) { - addParameter("namespace", result.substring(0, slash)); - } else { - addParameter("namespace", ""); - } - - // name/id: cut out anything between / and . should be the id and name - if (id == null) { - slash = result.lastIndexOf('/'); - int dot = result.indexOf('.', slash); - if (dot != -1) { - id = result.substring(slash + 1, dot); - } else { - id = result.substring(slash + 1); - } - addParameter("id", escape(id)); - } - } - - // WW-1284 - // evaluate if client-side js is to be enabled. (if validation interceptor - // does allow validation eg. method is not filtered out) - evaluateClientSideJsEnablement(actionName, namespace, actionMethod); - } - - private void evaluateClientSideJsEnablement(String actionName, String namespace, String actionMethod) { + protected void evaluateClientSideJsEnablement(String actionName, String namespace, String actionMethod) { // Only evaluate if Client-Side js is to be enable when validate=true Boolean validate = (Boolean) getParameters().get("validate"); @@ -361,53 +274,6 @@ public class Form extends ClosingUIBean { } } - /** - * Constructs the action url adapted to a portal environment. - * - * @param action The action to create the URL for. - */ - private void evaluateExtraParamsPortletRequest(String namespace, String action) { - - if (this.action != null) { - // if it isn't specified, we'll make somethig up - action = findString(this.action); - } - - String type = "action"; - if (TextUtils.stringSet(method)) { - if ("GET".equalsIgnoreCase(method.trim())) { - type = "render"; - } - } - if (action != null) { - String result = PortletUrlHelper.buildUrl(action, namespace, - getParameters(), type, portletMode, windowState); - addParameter("action", result); - - // namespace: cut out anything between the start and the last / - int slash = result.lastIndexOf('/'); - if (slash != -1) { - addParameter("namespace", result.substring(0, slash)); - } else { - addParameter("namespace", ""); - } - - // name/id: cut out anything between / and . should be the id and - // name - 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); - } - addParameter("id", escape(id)); - } - } - - } - public List getValidators(String name) { Class actionClass = (Class) getParameters().get("actionClass"); if (actionClass == null) { diff --git a/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java b/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java new file mode 100644 index 000000000..72935ef14 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java @@ -0,0 +1,173 @@ +package org.apache.struts2.components; + +import java.io.IOException; +import java.io.Writer; + +import org.apache.struts2.StrutsException; +import org.apache.struts2.dispatcher.mapper.ActionMapping; +import org.apache.struts2.views.util.UrlHelper; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.config.entities.ActionConfig; + +/** + * Implementation of the {@link UrlRenderer} interface that creates URLs suitable in a servlet environment. + * + */ +public class ServletUrlRenderer 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 = urlComponent.determineActionURL(urlComponent.action, urlComponent.namespace, urlComponent.method, urlComponent.req, urlComponent.res, urlComponent.parameters, scheme, urlComponent.includeContext, urlComponent.encode); + } else { + String _value = urlComponent.value; + + // We don't include the request parameters cause they would have been + // prioritised before this [in start(Writer) method] + if (_value != null && _value.indexOf("?") > 0) { + _value = _value.substring(0, _value.indexOf("?")); + } + result = UrlHelper.buildUrl(_value, urlComponent.req, urlComponent.res, urlComponent.parameters, scheme, urlComponent.includeContext, urlComponent.encode); + } + 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 namespace = formComponent.determineNamespace(formComponent.namespace, formComponent.getStack(), + formComponent.request); + String action = null; + + if(formComponent.action != null) { + action = formComponent.findString(formComponent.action); + } + + if (formComponent.action == null) { + // no action supplied? ok, then default to the current request + // (action or general URL) + ActionInvocation ai = (ActionInvocation) formComponent.getStack().getContext().get( + ActionContext.ACTION_INVOCATION); + if (ai != null) { + action = ai.getProxy().getActionName(); + namespace = ai.getProxy().getNamespace(); + } else { + // hmm, ok, we need to just assume the current URL cut down + String uri = formComponent.request.getRequestURI(); + action = uri.substring(uri.lastIndexOf('/')); + } + } + + String actionMethod = ""; + // FIXME: our implementation is flawed - the only concept of ! should be + // in DefaultActionMapper + // handle "name!method" convention. + if (formComponent.enableDynamicMethodInvocation) { + if (action.indexOf("!") != -1) { + int endIdx = action.lastIndexOf("!"); + actionMethod = action.substring(endIdx + 1, action.length()); + action = action.substring(0, endIdx); + } + } + + final ActionConfig actionConfig = formComponent.configuration.getRuntimeConfiguration().getActionConfig( + namespace, action); + String actionName = action; + if (actionConfig != null) { + + ActionMapping mapping = new ActionMapping(action, namespace, actionMethod, formComponent.parameters); + String result = UrlHelper.buildUrl(formComponent.actionMapper.getUriFromActionMapping(mapping), + formComponent.request, formComponent.response, null); + formComponent.addParameter("action", result); + + // let's try to get the actual action class and name + // this can be used for getting the list of validators + formComponent.addParameter("actionName", actionName); + try { + Class clazz = formComponent.objectFactory.getClassInstance(actionConfig.getClassName()); + formComponent.addParameter("actionClass", clazz); + } catch (ClassNotFoundException e) { + // this is OK, we'll just move on + } + + formComponent.addParameter("namespace", namespace); + + // if the name isn't specified, use the action name + if (formComponent.name == null) { + formComponent.addParameter("name", action); + } + + // if the id isn't specified, use the action name + if (formComponent.getId() == null) { + formComponent.addParameter("id", action); + } + } else if (action != null) { + // Since we can't find an action alias in the configuration, we just + // assume + // the action attribute supplied is the path to be used as the uri + // this + // form is submitting to. + + String result = UrlHelper.buildUrl(action, formComponent.request, formComponent.response, null); + 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 = result.lastIndexOf('/'); + int dot = result.indexOf('.', slash); + if (dot != -1) { + id = result.substring(slash + 1, dot); + } else { + id = result.substring(slash + 1); + } + formComponent.addParameter("id", formComponent.escape(id)); + } + } + + // WW-1284 + // evaluate if client-side js is to be enabled. (if validation + // interceptor + // does allow validation eg. method is not filtered out) + formComponent.evaluateClientSideJsEnablement(actionName, namespace, actionMethod); + } + +} diff --git a/core/src/main/java/org/apache/struts2/components/URL.java b/core/src/main/java/org/apache/struts2/components/URL.java index b9de4e46f..e5d046561 100644 --- a/core/src/main/java/org/apache/struts2/components/URL.java +++ b/core/src/main/java/org/apache/struts2/components/URL.java @@ -37,8 +37,6 @@ import org.apache.struts2.views.annotations.StrutsTagAttribute; import org.apache.struts2.StrutsException; import org.apache.struts2.StrutsConstants; import org.apache.struts2.dispatcher.Dispatcher; -import org.apache.struts2.portlet.context.PortletActionContext; -import org.apache.struts2.portlet.util.PortletUrlHelper; import org.apache.struts2.views.util.UrlHelper; import com.opensymphony.xwork2.inject.Inject; @@ -125,8 +123,8 @@ public class URL extends ContextBean { public static final String GET = "get"; public static final String ALL = "all"; - private HttpServletRequest req; - private HttpServletResponse res; + protected HttpServletRequest req; + protected HttpServletResponse res; protected String includeParams; protected String scheme; @@ -142,6 +140,7 @@ public class URL extends ContextBean { protected String anchor; protected String urlIncludeParams; protected ExtraParameterProvider extraParameterProvider; + protected UrlRenderer urlRenderer; public URL(ValueStack stack, HttpServletRequest req, HttpServletResponse res) { super(stack); @@ -153,6 +152,11 @@ public class URL extends ContextBean { public void setUrlIncludeParams(String urlIncludeParams) { this.urlIncludeParams = urlIncludeParams; } + + @Inject + public void setUrlRenderer(UrlRenderer urlRenderer) { + this.urlRenderer = urlRenderer; + } @Inject(required=false) public void setExtraParameterProvider(ExtraParameterProvider provider) { @@ -204,10 +208,8 @@ public class URL extends ContextBean { } } private void includeGetParameters() { - if(!(Dispatcher.getInstance().isPortletSupportActive() && PortletActionContext.isPortletRequest())) { - String query = extractQueryString(); - mergeRequestParameters(value, parameters, UrlHelper.parseQueryString(query)); - } + String query = extractQueryString(); + mergeRequestParameters(value, parameters, UrlHelper.parseQueryString(query)); } private String extractQueryString() { @@ -229,53 +231,7 @@ public class URL extends ContextBean { } public boolean end(Writer writer, String body) { - String scheme = req.getScheme(); - - if (this.scheme != null) { - scheme = this.scheme; - } - - String result; - if (value == null && action != null) { - if(Dispatcher.getInstance().isPortletSupportActive() && PortletActionContext.isPortletRequest()) { - result = PortletUrlHelper.buildUrl(action, namespace, parameters, portletUrlType, portletMode, windowState); - } - else { - result = determineActionURL(action, namespace, method, req, res, parameters, scheme, includeContext, encode); - } - } else { - if(Dispatcher.getInstance().isPortletSupportActive() && PortletActionContext.isPortletRequest()) { - result = PortletUrlHelper.buildResourceUrl(value, parameters); - } - else { - String _value = value; - - // We don't include the request parameters cause they would have been - // prioritised before this [in start(Writer) method] - if (_value != null && _value.indexOf("?") > 0) { - _value = _value.substring(0, _value.indexOf("?")); - } - result = UrlHelper.buildUrl(_value, req, res, parameters, scheme, includeContext, encode); - } - } - if ( anchor != null && anchor.length() > 0 ) { - result += '#' + anchor; - } - - String var = getVar(); - - if (var != null) { - putInContext(result); - - // add to the request and page scopes as well - req.setAttribute(var, result); - } else { - try { - writer.write(result); - } catch (IOException e) { - throw new StrutsException("IOError: " + e.getMessage(), e); - } - } + urlRenderer.renderUrl(writer, this); return super.end(writer, body); } diff --git a/core/src/main/java/org/apache/struts2/components/UrlRenderer.java b/core/src/main/java/org/apache/struts2/components/UrlRenderer.java new file mode 100644 index 000000000..fa35bca29 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/components/UrlRenderer.java @@ -0,0 +1,23 @@ +package org.apache.struts2.components; + +import java.io.Writer; + +/** + * Implementations of this interface are responsible for rendering/creating URLs for a specific + * environment (e.g. Servlet, Portlet). + * + */ +public interface UrlRenderer { + /** + * Render a URL. + * @param writer A writer that the implementation can use to write the result to. + * @param urlComponent The {@link URL} component that "owns" this renderer. + */ + void renderUrl(Writer writer, URL urlComponent); + + /** + * Render a Form URL. + * @param formComponent The {@link Form} component that "owns" this renderer. + */ + void renderFormUrl(Form formComponent); +} diff --git a/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java b/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java index d9bbbce6e..e95714d77 100644 --- a/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java +++ b/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java @@ -26,6 +26,7 @@ import java.util.StringTokenizer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts2.StrutsConstants; +import org.apache.struts2.components.UrlRenderer; import org.apache.struts2.dispatcher.mapper.ActionMapper; import org.apache.struts2.dispatcher.multipart.MultiPartRequest; import org.apache.struts2.views.freemarker.FreemarkerManager; @@ -159,6 +160,7 @@ public class BeanSelectionProvider implements ConfigurationProvider { alias(MultiPartRequest.class, StrutsConstants.STRUTS_MULTIPART_PARSER, builder, props, Scope.DEFAULT); alias(FreemarkerManager.class, StrutsConstants.STRUTS_FREEMARKER_MANAGER_CLASSNAME, builder, props); alias(VelocityManager.class, StrutsConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME, builder, props); + alias(UrlRenderer.class, StrutsConstants.STRUTS_URL_RENDERER, builder, props); if ("true".equalsIgnoreCase(props.getProperty(StrutsConstants.STRUTS_DEVMODE))) { props.setProperty(StrutsConstants.STRUTS_I18N_RELOAD, "true"); diff --git a/core/src/main/java/org/apache/struts2/interceptor/ServletConfigInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ServletConfigInterceptor.java index 8742e5bd5..092003231 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/ServletConfigInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/ServletConfigInterceptor.java @@ -25,12 +25,9 @@ import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.portlet.PortletRequest; import org.apache.struts2.StrutsStatics; import org.apache.struts2.servlet.interceptor.ServletPrincipalProxy; -import org.apache.struts2.portlet.PortletActionConstants; -import org.apache.struts2.portlet.interceptor.PortletPrincipalProxy; import org.apache.struts2.util.ServletContextAware; import com.opensymphony.xwork2.ActionContext; @@ -154,11 +151,7 @@ public class ServletConfigInterceptor extends AbstractInterceptor implements Str if (action instanceof PrincipalAware) { HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST); - Object portletRequest = context.get(PortletActionConstants.REQUEST); - if (portletRequest != null) { - // We are in portlet environment, so principal information resides in PortletRequest - ((PrincipalAware) action).setPrincipalProxy(new PortletPrincipalProxy((PortletRequest) portletRequest)); - } else { + if(request != null) { // We are in servtlet environment, so principal information resides in HttpServletRequest ((PrincipalAware) action).setPrincipalProxy(new ServletPrincipalProxy(request)); } diff --git a/core/src/test/java/org/apache/struts2/interceptor/ServletConfigInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/ServletConfigInterceptorTest.java index 9fd4f6f35..a06535fe7 100644 --- a/core/src/test/java/org/apache/struts2/interceptor/ServletConfigInterceptorTest.java +++ b/core/src/test/java/org/apache/struts2/interceptor/ServletConfigInterceptorTest.java @@ -133,12 +133,16 @@ public class ServletConfigInterceptorTest extends StrutsTestCase { } public void testPrincipalAware() throws Exception { + MockHttpServletRequest req = new MockHttpServletRequest(); + req.setUserPrincipal(null); + req.setRemoteUser("Santa"); MockControl control = MockControl.createControl(PrincipalAware.class); control.setDefaultMatcher(MockControl.ALWAYS_MATCHER); // less strick match is needed for this unit test to be conducted using mocks PrincipalAware mock = (PrincipalAware) control.getMock(); MockActionInvocation mai = createActionInvocation(mock); - + mai.getInvocationContext().put(StrutsStatics.HTTP_REQUEST, req); + MockServletContext ctx = new MockServletContext(); mai.getInvocationContext().put(StrutsStatics.SERVLET_CONTEXT, ctx); diff --git a/core/src/test/java/org/apache/struts2/portlet/util/StrutsUtilTest.java b/core/src/test/java/org/apache/struts2/util/StrutsUtilTest.java similarity index 99% rename from core/src/test/java/org/apache/struts2/portlet/util/StrutsUtilTest.java rename to core/src/test/java/org/apache/struts2/util/StrutsUtilTest.java index c22ae0ec6..4a42f79f9 100644 --- a/core/src/test/java/org/apache/struts2/portlet/util/StrutsUtilTest.java +++ b/core/src/test/java/org/apache/struts2/util/StrutsUtilTest.java @@ -18,7 +18,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.struts2.portlet.util; +package org.apache.struts2.util; import java.util.ArrayList; import java.util.List; diff --git a/plugins/pom.xml b/plugins/pom.xml index 7f013aadf..b38e9287d 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -32,6 +32,7 @@ struts1 tiles dojo + portlet diff --git a/plugins/portlet/pom.xml b/plugins/portlet/pom.xml new file mode 100644 index 000000000..8e0ecf77b --- /dev/null +++ b/plugins/portlet/pom.xml @@ -0,0 +1,107 @@ + + + 4.0.0 + + org.apache.struts + struts2-plugins + 2.1.0-SNAPSHOT + + org.apache.struts + struts2-portlet-plugin + jar + Struts 2 Portlet Plugin + + + scm:svn:http://svn.apache.org/repos/asf/struts/struts2/trunk/plugins/portlet/ + scm:svn:https://svn.apache.org/repos/asf/struts/struts2/trunk/plugins/portlet/ + http://svn.apache.org/viewcvs.cgi/struts/struts2/trunk/plugins/portlet/ + + + + + junit + junit + test + 3.8.1 + + + + javax.servlet + jsp-api + 2.0 + provided + + + + + velocity + velocity + 1.4 + true + + + + velocity-tools + velocity-tools + 1.1 + true + + + + + portlet-api + portlet-api + 1.0 + true + + + + mockobjects + mockobjects-jdk1.3-j2ee1.3 + 0.09 + test + + + + org.easymock + easymock + 2.0 + test + + + jmock + jmock + 1.0.1 + test + + + + jmock + jmock-cglib + 1.0.1 + test + + + + mockobjects + mockobjects-core + 0.09 + test + + + + + org.springframework + spring-mock + 1.2.8 + true + + + org.springframework + spring-core + 1.2.8 + test + + + diff --git a/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java b/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java new file mode 100644 index 000000000..bbba8f722 --- /dev/null +++ b/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java @@ -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)); + } + } + + + } + +} diff --git a/core/src/main/java/org/apache/struts2/portlet/PortletActionConstants.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/PortletActionConstants.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/PortletActionConstants.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/PortletActionConstants.java diff --git a/core/src/main/java/org/apache/struts2/portlet/PortletApplicationMap.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/PortletApplicationMap.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/PortletApplicationMap.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/PortletApplicationMap.java diff --git a/core/src/main/java/org/apache/struts2/portlet/PortletRequestMap.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/PortletRequestMap.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/PortletRequestMap.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/PortletRequestMap.java diff --git a/core/src/main/java/org/apache/struts2/portlet/PortletSessionMap.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/PortletSessionMap.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/PortletSessionMap.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/PortletSessionMap.java diff --git a/core/src/main/java/org/apache/struts2/portlet/context/PortletActionContext.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/context/PortletActionContext.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/context/PortletActionContext.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/context/PortletActionContext.java diff --git a/core/src/main/java/org/apache/struts2/portlet/context/PreparatorServlet.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/context/PreparatorServlet.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/context/PreparatorServlet.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/context/PreparatorServlet.java diff --git a/core/src/main/java/org/apache/struts2/portlet/context/ServletContextHolderListener.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/context/ServletContextHolderListener.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/context/ServletContextHolderListener.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/context/ServletContextHolderListener.java diff --git a/core/src/main/java/org/apache/struts2/portlet/dispatcher/DirectRenderFromEventAction.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/dispatcher/DirectRenderFromEventAction.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/dispatcher/DirectRenderFromEventAction.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/dispatcher/DirectRenderFromEventAction.java diff --git a/core/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java similarity index 99% rename from core/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java index 777cb09e9..489657470 100644 --- a/core/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java +++ b/plugins/portlet/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java @@ -36,6 +36,7 @@ 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; @@ -300,6 +301,7 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics, 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), @@ -310,6 +312,7 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics, } finally { resetActionContext(); } + } } /** diff --git a/core/src/main/java/org/apache/struts2/portlet/interceptor/PortletPreferencesAware.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/interceptor/PortletPreferencesAware.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/interceptor/PortletPreferencesAware.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/interceptor/PortletPreferencesAware.java diff --git a/core/src/main/java/org/apache/struts2/portlet/interceptor/PortletPreferencesInterceptor.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/interceptor/PortletPreferencesInterceptor.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/interceptor/PortletPreferencesInterceptor.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/interceptor/PortletPreferencesInterceptor.java diff --git a/core/src/main/java/org/apache/struts2/portlet/interceptor/PortletPrincipalProxy.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/interceptor/PortletPrincipalProxy.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/interceptor/PortletPrincipalProxy.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/interceptor/PortletPrincipalProxy.java diff --git a/core/src/main/java/org/apache/struts2/portlet/interceptor/ServletPortletPreferences.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/interceptor/ServletPortletPreferences.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/interceptor/ServletPortletPreferences.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/interceptor/ServletPortletPreferences.java diff --git a/core/src/main/java/org/apache/struts2/portlet/result/PortletResult.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletResult.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/result/PortletResult.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletResult.java diff --git a/core/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/result/PortletVelocityResult.java diff --git a/core/src/main/java/org/apache/struts2/portlet/util/HttpServletRequestMock.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/util/HttpServletRequestMock.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/util/HttpServletRequestMock.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/util/HttpServletRequestMock.java diff --git a/core/src/main/java/org/apache/struts2/portlet/util/PortletUrlHelper.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/util/PortletUrlHelper.java similarity index 100% rename from core/src/main/java/org/apache/struts2/portlet/util/PortletUrlHelper.java rename to plugins/portlet/src/main/java/org/apache/struts2/portlet/util/PortletUrlHelper.java diff --git a/core/src/main/java/org/apache/struts2/views/freemarker/PortletFreemarkerResult.java b/plugins/portlet/src/main/java/org/apache/struts2/views/freemarker/PortletFreemarkerResult.java similarity index 100% rename from core/src/main/java/org/apache/struts2/views/freemarker/PortletFreemarkerResult.java rename to plugins/portlet/src/main/java/org/apache/struts2/views/freemarker/PortletFreemarkerResult.java diff --git a/plugins/portlet/src/main/resources/LICENSE.txt b/plugins/portlet/src/main/resources/LICENSE.txt new file mode 100644 index 000000000..c6055ec8f --- /dev/null +++ b/plugins/portlet/src/main/resources/LICENSE.txt @@ -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. diff --git a/plugins/portlet/src/main/resources/NOTICE.txt b/plugins/portlet/src/main/resources/NOTICE.txt new file mode 100644 index 000000000..24a821800 --- /dev/null +++ b/plugins/portlet/src/main/resources/NOTICE.txt @@ -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/). \ No newline at end of file diff --git a/plugins/portlet/src/main/resources/struts-plugin.xml b/plugins/portlet/src/main/resources/struts-plugin.xml new file mode 100644 index 000000000..434509ce5 --- /dev/null +++ b/plugins/portlet/src/main/resources/struts-plugin.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${location} + + + ${location} + + + ${location} + + + diff --git a/core/src/test/java/org/apache/struts2/portlet/PortletApplicationMapTest.java b/plugins/portlet/src/test/java/org/apache/struts2/portlet/PortletApplicationMapTest.java similarity index 100% rename from core/src/test/java/org/apache/struts2/portlet/PortletApplicationMapTest.java rename to plugins/portlet/src/test/java/org/apache/struts2/portlet/PortletApplicationMapTest.java diff --git a/core/src/test/java/org/apache/struts2/portlet/PortletRequestMapTest.java b/plugins/portlet/src/test/java/org/apache/struts2/portlet/PortletRequestMapTest.java similarity index 100% rename from core/src/test/java/org/apache/struts2/portlet/PortletRequestMapTest.java rename to plugins/portlet/src/test/java/org/apache/struts2/portlet/PortletRequestMapTest.java diff --git a/core/src/test/java/org/apache/struts2/portlet/PortletSessionMapTest.java b/plugins/portlet/src/test/java/org/apache/struts2/portlet/PortletSessionMapTest.java similarity index 100% rename from core/src/test/java/org/apache/struts2/portlet/PortletSessionMapTest.java rename to plugins/portlet/src/test/java/org/apache/struts2/portlet/PortletSessionMapTest.java diff --git a/core/src/test/java/org/apache/struts2/portlet/context/PortletActionContextTest.java b/plugins/portlet/src/test/java/org/apache/struts2/portlet/context/PortletActionContextTest.java similarity index 100% rename from core/src/test/java/org/apache/struts2/portlet/context/PortletActionContextTest.java rename to plugins/portlet/src/test/java/org/apache/struts2/portlet/context/PortletActionContextTest.java diff --git a/core/src/test/java/org/apache/struts2/portlet/context/PreparatorServletTest.java b/plugins/portlet/src/test/java/org/apache/struts2/portlet/context/PreparatorServletTest.java similarity index 100% rename from core/src/test/java/org/apache/struts2/portlet/context/PreparatorServletTest.java rename to plugins/portlet/src/test/java/org/apache/struts2/portlet/context/PreparatorServletTest.java diff --git a/core/src/test/java/org/apache/struts2/portlet/context/ServletContextHolderListenerTest.java b/plugins/portlet/src/test/java/org/apache/struts2/portlet/context/ServletContextHolderListenerTest.java similarity index 100% rename from core/src/test/java/org/apache/struts2/portlet/context/ServletContextHolderListenerTest.java rename to plugins/portlet/src/test/java/org/apache/struts2/portlet/context/ServletContextHolderListenerTest.java diff --git a/core/src/test/java/org/apache/struts2/portlet/dispatcher/Jsr168DispatcherTest.java b/plugins/portlet/src/test/java/org/apache/struts2/portlet/dispatcher/Jsr168DispatcherTest.java similarity index 100% rename from core/src/test/java/org/apache/struts2/portlet/dispatcher/Jsr168DispatcherTest.java rename to plugins/portlet/src/test/java/org/apache/struts2/portlet/dispatcher/Jsr168DispatcherTest.java diff --git a/core/src/test/java/org/apache/struts2/portlet/result/PortletResultTest.java b/plugins/portlet/src/test/java/org/apache/struts2/portlet/result/PortletResultTest.java similarity index 100% rename from core/src/test/java/org/apache/struts2/portlet/result/PortletResultTest.java rename to plugins/portlet/src/test/java/org/apache/struts2/portlet/result/PortletResultTest.java diff --git a/core/src/test/java/org/apache/struts2/portlet/util/PortletUrlHelperTest.java b/plugins/portlet/src/test/java/org/apache/struts2/portlet/util/PortletUrlHelperTest.java similarity index 100% rename from core/src/test/java/org/apache/struts2/portlet/util/PortletUrlHelperTest.java rename to plugins/portlet/src/test/java/org/apache/struts2/portlet/util/PortletUrlHelperTest.java diff --git a/core/src/test/java/org/apache/struts2/views/jsp/PortletUrlTagTest.java b/plugins/portlet/src/test/java/org/apache/struts2/views/jsp/PortletUrlTagTest.java similarity index 100% rename from core/src/test/java/org/apache/struts2/views/jsp/PortletUrlTagTest.java rename to plugins/portlet/src/test/java/org/apache/struts2/views/jsp/PortletUrlTagTest.java