Author: musachy Date: Tue May 13 15:18:17 2008 New Revision: 656033 URL: http://svn.apache.org/viewvc?rev=656033&view=rev Log: [WW-1796] @InterceptorRef and @InterceptorRefs annotations to configure actions with custom interceptor-refs
(interceptor params still missing) thanks to Aadi Deshpande for the patch Added: struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/annotation/InterceptorRef.java struts/sandbox/trunk/struts2-convention-plugin/src/test/java/org/apache/struts2/convention/actions/interceptor/ struts/sandbox/trunk/struts2-convention-plugin/src/test/java/org/apache/struts2/convention/actions/interceptor/InterceptorsAction.java Modified: struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/annotation/Action.java struts/sandbox/trunk/struts2-convention-plugin/src/test/java/org/apache/struts2/convention/PackageBasedActionConfigBuilderTest.java Modified: struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java?rev=656033&r1=656032&r2=656033&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java (original) +++ struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java Tue May 13 15:18:17 2008 @@ -27,6 +27,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -34,6 +35,7 @@ import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Actions; import org.apache.struts2.convention.annotation.AnnotationTools; +import org.apache.struts2.convention.annotation.InterceptorRef; import org.apache.struts2.convention.annotation.Namespace; import org.apache.struts2.convention.annotation.ParentPackage; @@ -41,8 +43,10 @@ import com.opensymphony.xwork2.config.Configuration; import com.opensymphony.xwork2.config.ConfigurationException; import com.opensymphony.xwork2.config.entities.ActionConfig; +import com.opensymphony.xwork2.config.entities.InterceptorMapping; import com.opensymphony.xwork2.config.entities.PackageConfig; import com.opensymphony.xwork2.config.entities.ResultConfig; +import com.opensymphony.xwork2.config.providers.InterceptorBuilder; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; @@ -421,12 +425,40 @@ actionClass.toString(), actionName, pkgCfg.getName(), pkgCfg.getNamespace()); } + //build interceptors + List<InterceptorMapping> interceptors = buildInterceptors(pkgCfg, actionName, annotation); + actionConfig.addInterceptors(interceptors); + + //build results Map<String, ResultConfig> results = resultMapBuilder.build(actionClass, annotation, actionName, pkgCfg.build()); actionConfig.addResultConfigs(results); pkgCfg.addActionConfig(actionName, actionConfig.build()); } + private List<InterceptorMapping> buildInterceptors(PackageConfig.Builder builder, String actionName, Action annotation) { + List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(10); + + if (annotation != null) { + InterceptorRef[] interceptors = annotation.interceptorRefs(); + if (interceptors != null) { + for (InterceptorRef interceptor : interceptors) { + if (LOG.isTraceEnabled()) + LOG.trace("Adding interceptor [#0] to [#1]", interceptor.value(), actionName); + interceptorList.addAll(buildInterceptorList(builder, interceptor)); + } + } + } + + return interceptorList; + } + + private List<InterceptorMapping> buildInterceptorList(PackageConfig.Builder builder, InterceptorRef ref) { + return InterceptorBuilder.constructInterceptorReference(builder, ref.value(), new LinkedHashMap(), + builder.build().getLocation(), (ObjectFactory) configuration.getContainer().getInstance( + ObjectFactory.class)); + } + private PackageConfig.Builder getPackageConfig(final Map<String, PackageConfig.Builder> packageConfigs, String actionNamespace, final String actionPackage, final Class<?> actionClass, Action action) { Modified: struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/annotation/Action.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/annotation/Action.java?rev=656033&r1=656032&r2=656033&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/annotation/Action.java (original) +++ struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/annotation/Action.java Tue May 13 15:18:17 2008 @@ -74,4 +74,10 @@ * @return The results for the action. */ Result[] results() default {}; + + /** + * Allows action methods to specify what interceptors must be applied to it. + * @return Interceptors to be applied to the action + */ + InterceptorRef[] interceptorRefs() default {}; } \ No newline at end of file Added: struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/annotation/InterceptorRef.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/annotation/InterceptorRef.java?rev=656033&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/annotation/InterceptorRef.java (added) +++ struts/sandbox/trunk/struts2-convention-plugin/src/main/java/org/apache/struts2/convention/annotation/InterceptorRef.java Tue May 13 15:18:17 2008 @@ -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.convention.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * <!-- START SNIPPET: javadoc --> + * <p> + * This annotation allows interceptor to be applied to acctions + * </p> + * <!-- END SNIPPET: javadoc --> + */ [EMAIL PROTECTED](RetentionPolicy.RUNTIME) [EMAIL PROTECTED](ElementType.TYPE) +public @interface InterceptorRef { + String value(); +} Modified: struts/sandbox/trunk/struts2-convention-plugin/src/test/java/org/apache/struts2/convention/PackageBasedActionConfigBuilderTest.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-convention-plugin/src/test/java/org/apache/struts2/convention/PackageBasedActionConfigBuilderTest.java?rev=656033&r1=656032&r2=656033&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-convention-plugin/src/test/java/org/apache/struts2/convention/PackageBasedActionConfigBuilderTest.java (original) +++ struts/sandbox/trunk/struts2-convention-plugin/src/test/java/org/apache/struts2/convention/PackageBasedActionConfigBuilderTest.java Tue May 13 15:18:17 2008 @@ -20,8 +20,11 @@ */ package org.apache.struts2.convention; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Set; import junit.framework.TestCase; @@ -33,6 +36,7 @@ import org.apache.struts2.convention.actions.action.ActionNamesAction; import org.apache.struts2.convention.actions.action.SingleActionNameAction; import org.apache.struts2.convention.actions.action.TestAction; +import org.apache.struts2.convention.actions.interceptor.InterceptorsAction; import org.apache.struts2.convention.actions.namespace.ActionLevelNamespaceAction; import org.apache.struts2.convention.actions.namespace.ClassLevelNamespaceAction; import org.apache.struts2.convention.actions.namespace.PackageLevelNamespaceAction; @@ -52,13 +56,24 @@ import org.easymock.EasyMock; import static org.easymock.EasyMock.*; +import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.ObjectFactory; import com.opensymphony.xwork2.config.Configuration; import com.opensymphony.xwork2.config.entities.ActionConfig; +import com.opensymphony.xwork2.config.entities.InterceptorConfig; +import com.opensymphony.xwork2.config.entities.InterceptorMapping; +import com.opensymphony.xwork2.config.entities.InterceptorStackConfig; import com.opensymphony.xwork2.config.entities.PackageConfig; import com.opensymphony.xwork2.config.entities.ResultConfig; import com.opensymphony.xwork2.config.entities.ResultTypeConfig; import com.opensymphony.xwork2.config.impl.DefaultConfiguration; +import com.opensymphony.xwork2.inject.Container; +import com.opensymphony.xwork2.inject.Scope.Strategy; +import com.opensymphony.xwork2.interceptor.AbstractInterceptor; +import com.opensymphony.xwork2.interceptor.Interceptor; +import com.opensymphony.xwork2.ognl.OgnlReflectionProvider; +import com.opensymphony.xwork2.util.reflection.ReflectionProvider; +import com.opensymphony.xwork2.validator.ValidationInterceptor; /** * <p> @@ -75,9 +90,24 @@ } private void run(String actionPackages, String packageLocators, String excludePackages) { + //setup interceptors + List<InterceptorConfig> defaultInterceptors = new ArrayList<InterceptorConfig>(); + defaultInterceptors.add(makeInterceptorConfig("interceptor-1")); + defaultInterceptors.add(makeInterceptorConfig("interceptor-2")); + defaultInterceptors.add(makeInterceptorConfig("interceptor-3")); + + //setup interceptor stacks + List<InterceptorStackConfig> defaultInterceptorStacks = new ArrayList<InterceptorStackConfig>(); + defaultInterceptorStacks.add(makeInterceptorStackConfig("stack-1", "interceptor-1", "interceptor-2")); + defaultInterceptorStacks.add(makeInterceptorStackConfig("stack-2", "interceptor-3", "stack-1")); + + //setup results + ResultTypeConfig[] defaultResults = new ResultTypeConfig[] { new ResultTypeConfig.Builder("dispatcher", + ServletDispatcherResult.class.getName()).defaultResultParam("location").build() }; + PackageConfig strutsDefault = makePackageConfig("struts-default", null, null, "dispatcher", - new ResultTypeConfig.Builder("dispatcher", ServletDispatcherResult.class.getName()). - defaultResultParam("location").build()); + defaultResults, defaultInterceptors, defaultInterceptorStacks); + PackageConfig packageLevelParentPkg = makePackageConfig("package-level", null, null, null); PackageConfig classLevelParentPkg = makePackageConfig("class-level", null, null, null); @@ -89,6 +119,8 @@ "/idx", strutsDefault, null); PackageConfig idx2Pkg = makePackageConfig("org.apache.struts2.convention.actions.idx.idx2#struts-default#/idx/idx2", "/idx/idx2", strutsDefault, null); + PackageConfig interceptorRefsPkg = makePackageConfig("org.apache.struts2.convention.actions.interceptor#struts-default#/interceptor", + "/interceptor", strutsDefault, null); PackageConfig packageLevelPkg = makePackageConfig("org.apache.struts2.convention.actions.parentpackage#package-level#/parentpackage", "/parentpackage", packageLevelParentPkg, null); PackageConfig differentPkg = makePackageConfig("org.apache.struts2.convention.actions.parentpackage#class-level#/parentpackage", @@ -125,6 +157,11 @@ expect(resultMapBuilder.build(org.apache.struts2.convention.actions.idx.Index.class, null, "index", idxPkg)).andReturn(results); expect(resultMapBuilder.build(org.apache.struts2.convention.actions.idx.idx2.Index.class, null, "index", idx2Pkg)).andReturn(results); + /* org.apache.struts2.convention.actions.interceptor */ + expect(resultMapBuilder.build(InterceptorsAction.class, getAnnotation(InterceptorsAction.class, "run1", Action.class), "action100", interceptorRefsPkg)).andReturn(results); + expect(resultMapBuilder.build(InterceptorsAction.class, getAnnotation(InterceptorsAction.class, "run2", Action.class), "action200", interceptorRefsPkg)).andReturn(results); + expect(resultMapBuilder.build(InterceptorsAction.class, getAnnotation(InterceptorsAction.class, "run3", Action.class), "action300", interceptorRefsPkg)).andReturn(results); + /* org.apache.struts2.convention.actions.namespace */ expect(resultMapBuilder.build(ActionLevelNamespaceAction.class, getAnnotation(ActionLevelNamespaceAction.class, "execute", Action.class), "action", actionLevelNamespacePkg)).andReturn(results); expect(resultMapBuilder.build(ClassLevelNamespaceAction.class, null, "class-level-namespace", classLevelNamespacePkg)).andReturn(results); @@ -157,7 +194,15 @@ EasyMock.replay(resultMapBuilder); - Configuration configuration = new DefaultConfiguration(); + Configuration configuration = new DefaultConfiguration() { + + @Override + public Container getContainer() { + return new DummyContainer(); + } + + }; + configuration.addPackageConfig("struts-default", strutsDefault); configuration.addPackageConfig("package-level", packageLevelParentPkg); configuration.addPackageConfig("class-level", classLevelParentPkg); @@ -257,6 +302,15 @@ verifyActionConfig(pkgConfig, "class-level-result-path", ClassLevelResultPathAction.class, "execute", pkgConfig.getName()); verifyActionConfig(pkgConfig, "package-level-result-path", PackageLevelResultPathAction.class, "execute", pkgConfig.getName()); + /* org.apache.struts2.convention.actions.interceptorRefs */ + pkgConfig = configuration.getPackageConfig("org.apache.struts2.convention.actions.interceptor#struts-default#/interceptor"); + assertNotNull(pkgConfig); + assertEquals(3, pkgConfig.getActionConfigs().size()); + verifyActionConfigInterceptors(pkgConfig, "action100", "interceptor-1"); + verifyActionConfigInterceptors(pkgConfig, "action200", "interceptor-1", "interceptor-2"); + verifyActionConfigInterceptors(pkgConfig, "action300", "interceptor-3", "stack-1"); + + /* org.apache.struts2.convention.actions */ pkgConfig = configuration.getPackageConfig("org.apache.struts2.convention.actions#struts-default#"); assertNotNull(pkgConfig); @@ -267,6 +321,7 @@ verifyActionConfig(pkgConfig, "skip", Skip.class, "execute", pkgConfig.getName()); verifyActionConfig(pkgConfig, "idx", org.apache.struts2.convention.actions.idx.Index.class, "execute", "org.apache.struts2.convention.actions.idx#struts-default#/idx"); + } private void verifyActionConfig(PackageConfig pkgConfig, String actionName, Class<?> actionClass, @@ -278,8 +333,24 @@ assertEquals(packageName, ac.getPackageName()); } + private void verifyActionConfigInterceptors(PackageConfig pkgConfig, String actionName, String... refs) { + ActionConfig ac = pkgConfig.getAllActionConfigs().get(actionName); + assertNotNull(ac); + List<InterceptorMapping> interceptorMappings = ac.getInterceptors(); + for (int i = 0; i < interceptorMappings.size(); i++) { + InterceptorMapping interceptorMapping = interceptorMappings.get(i); + assertEquals(refs[i], interceptorMapping.getName()); + } + } + private PackageConfig makePackageConfig(String name, String namespace, PackageConfig parent, String defaultResultType, ResultTypeConfig... results) { + return makePackageConfig(name, namespace, parent, defaultResultType, results, null, null); + } + + private PackageConfig makePackageConfig(String name, String namespace, PackageConfig parent, + String defaultResultType, ResultTypeConfig[] results, List<InterceptorConfig> interceptors, + List<InterceptorStackConfig> interceptorStacks) { PackageConfig.Builder builder = new PackageConfig.Builder(name); if (namespace != null) { builder.namespace(namespace); @@ -290,13 +361,37 @@ if (defaultResultType != null) { builder.defaultResultType(defaultResultType); } - for (ResultTypeConfig result : results) { - builder.addResultTypeConfig(result); + if (results != null) { + for (ResultTypeConfig result : results) { + builder.addResultTypeConfig(result); + } + } + if (interceptors != null) { + for (InterceptorConfig ref : interceptors) { + builder.addInterceptorConfig(ref); + } + } + if (interceptorStacks != null) { + for (InterceptorStackConfig ref : interceptorStacks) { + builder.addInterceptorStackConfig(ref); + } } return new MyPackageConfig(builder.build()); } + private InterceptorConfig makeInterceptorConfig(String name) { + InterceptorConfig.Builder builder = new InterceptorConfig.Builder(name, "com.opensymphony.xwork2.validator.ValidationInterceptor"); + return builder.build(); + } + + private InterceptorStackConfig makeInterceptorStackConfig(String name, String... interceptors) { + InterceptorStackConfig.Builder builder = new InterceptorStackConfig.Builder(name); + for (String interceptor : interceptors) + builder.addInterceptor(new InterceptorMapping(interceptor, new ValidationInterceptor())); + return builder.build(); + } + public class MyPackageConfig extends PackageConfig { protected MyPackageConfig(PackageConfig packageConfig) { super(packageConfig); @@ -308,4 +403,48 @@ getParents().get(0) == other.getParents().get(0) && getParents().size() == other.getParents().size(); } } + + public class DummyContainer implements Container { + + public <T> T getInstance(Class<T> type) { + try { + T obj = type.newInstance(); + if (obj instanceof ObjectFactory) { + ((ObjectFactory)obj).setReflectionProvider(new OgnlReflectionProvider() { + + @Override + public void setProperties(Map properties, Object o) { + } + }); + } + return obj; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public <T> T getInstance(Class<T> type, String name) { + return null; + } + + public Set<String> getInstanceNames(Class<?> type) { + return null; + } + + public void inject(Object o) { + + } + + public <T> T inject(Class<T> implementation) { + return null; + } + + public void removeScopeStrategy() { + + } + + public void setScopeStrategy(Strategy scopeStrategy) { + } + + } } \ No newline at end of file Added: struts/sandbox/trunk/struts2-convention-plugin/src/test/java/org/apache/struts2/convention/actions/interceptor/InterceptorsAction.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-convention-plugin/src/test/java/org/apache/struts2/convention/actions/interceptor/InterceptorsAction.java?rev=656033&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-convention-plugin/src/test/java/org/apache/struts2/convention/actions/interceptor/InterceptorsAction.java (added) +++ struts/sandbox/trunk/struts2-convention-plugin/src/test/java/org/apache/struts2/convention/actions/interceptor/InterceptorsAction.java Tue May 13 15:18:17 2008 @@ -0,0 +1,46 @@ +/* + * $Id: ActionLevelResultAction.java 655902 2008-05-13 15:15:12Z bpontarelli $ + * + * 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.convention.actions.interceptor; + +import org.apache.struts2.convention.annotation.Action; +import org.apache.struts2.convention.annotation.InterceptorRef; + +/** + * <p> + * This is a test action with multiple interceptors. + * </p> + */ +public class InterceptorsAction { + @Action(value = "action100", interceptorRefs = @InterceptorRef("interceptor-1")) + public String run1() { + return null; + } + + @Action(value = "action200", interceptorRefs = @InterceptorRef("stack-1")) + public String run2() { + return null; + } + + @Action(value = "action300", interceptorRefs = @InterceptorRef("stack-2")) + public String run3() { + return null; + } +} \ No newline at end of file