Author: musachy Date: Sun Apr 26 22:58:17 2009 New Revision: 768826 URL: http://svn.apache.org/viewvc?rev=768826&view=rev Log: WW-3101 @Action and @Actions should be able to be applied to classes, the method will be determined at runtime by Dynamic Action invocation mechanism
Added: struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationAction.java struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationDefaultMethodAction.java struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationsAction.java struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationsDefaultMethodAction.java Modified: struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/annotation/Action.java struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/annotation/Actions.java struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/PackageBasedActionConfigBuilderTest.java Modified: struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java?rev=768826&r1=768825&r2=768826&view=diff ============================================================================== --- struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java (original) +++ struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java Sun Apr 26 22:58:17 2009 @@ -40,6 +40,7 @@ import com.opensymphony.xwork2.util.finder.ClassLoaderInterfaceDelegate; import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; +import com.opensymphony.xwork2.util.logging.LoggerUtils; import org.apache.commons.lang.xwork.StringUtils; import org.apache.commons.lang.xwork.ObjectUtils; import org.apache.struts2.StrutsConstants; @@ -99,6 +100,8 @@ private boolean reload; private Set<String> fileProtocols; + private static final String DEFAULT_METHOD = "execute"; + /** * Constructs actions based on a list of packages. * @@ -459,6 +462,9 @@ Map<String, PackageConfig.Builder> packageConfigs = new HashMap<String, PackageConfig.Builder>(); for (Class<?> actionClass : classes) { + Actions actionsAnnotation = actionClass.getAnnotation(Actions.class); + Action actionAnnotation = actionClass.getAnnotation(Action.class); + // Skip classes that can't be instantiated if (cannotInstantiate(actionClass)) { if (LOG.isTraceEnabled()) @@ -485,7 +491,6 @@ List<String> namespaces = determineActionNamespace(actionClass); for (String namespace : namespaces) { String defaultActionName = determineActionName(actionClass); - String defaultActionMethod = "execute"; PackageConfig.Builder defaultPackageConfig = getPackageConfig(packageConfigs, namespace, actionPackage, actionClass, null); @@ -493,7 +498,10 @@ // configuration should still be built or not. Map<String, List<Action>> map = getActionAnnotations(actionClass); Set<String> actionNames = new HashSet<String>(); - if (!map.containsKey(defaultActionMethod) && ReflectionTools.containsMethod(actionClass, defaultActionMethod)) { + boolean hasDefaultMethod = ReflectionTools.containsMethod(actionClass, DEFAULT_METHOD); + if (!map.containsKey(DEFAULT_METHOD) + && hasDefaultMethod + && actionAnnotation == null && actionsAnnotation == null) { boolean found = false; for (String method : map.keySet()) { List<Action> actions = map.get(method); @@ -518,7 +526,7 @@ // Build the default if (!found) { - createActionConfig(defaultPackageConfig, actionClass, defaultActionName, defaultActionMethod, null); + createActionConfig(defaultPackageConfig, actionClass, defaultActionName, DEFAULT_METHOD, null); } } @@ -538,10 +546,18 @@ // some actions will not have any @Action or a default method, like the rest actions // where the action mapper is the one that finds the right method at runtime - if (map.isEmpty() && mapAllMatches) { - Action actionAnnotation = actionClass.getAnnotation(Action.class); + if (map.isEmpty() && mapAllMatches && actionAnnotation == null && actionsAnnotation == null) { createActionConfig(defaultPackageConfig, actionClass, defaultActionName, null, actionAnnotation); } + + //if there are @Actions or @Action at the class level, create the mappings for them + String methodName = hasDefaultMethod ? DEFAULT_METHOD : null; + if (actionsAnnotation != null) { + List<Action> actionAnnotations = checkActionsAnnotation(actionsAnnotation); + for (Action actionAnnotation2 : actionAnnotations) + createActionConfig(defaultPackageConfig, actionClass, defaultActionName, methodName, actionAnnotation2); + } else if (actionAnnotation != null) + createActionConfig(defaultPackageConfig, actionClass, defaultActionName, methodName, actionAnnotation); } } @@ -671,20 +687,7 @@ for (Method method : methods) { Actions actionsAnnotation = method.getAnnotation(Actions.class); if (actionsAnnotation != null) { - Action[] actionArray = actionsAnnotation.value(); - boolean valuelessSeen = false; - List<Action> actions = new ArrayList<Action>(); - for (Action ann : actionArray) { - if (ann.value().equals(Action.DEFAULT_VALUE) && !valuelessSeen) { - valuelessSeen = true; - } else if (ann.value().equals(Action.DEFAULT_VALUE)) { - throw new ConfigurationException("You may only add a single Action " + - "annotation that has no value parameter."); - } - - actions.add(ann); - } - + List<Action> actions = checkActionsAnnotation(actionsAnnotation); map.put(method.getName(), actions); } else { Action ann = method.getAnnotation(Action.class); @@ -698,6 +701,28 @@ } /** + * Builds a list of actions from an @Actions annotation, and check that they are not all empty + * @param actionsAnnotation Actions annotation + * @return a list of Actions + */ + protected List<Action> checkActionsAnnotation(Actions actionsAnnotation) { + Action[] actionArray = actionsAnnotation.value(); + boolean valuelessSeen = false; + List<Action> actions = new ArrayList<Action>(); + for (Action ann : actionArray) { + if (ann.value().equals(Action.DEFAULT_VALUE) && !valuelessSeen) { + valuelessSeen = true; + } else if (ann.value().equals(Action.DEFAULT_VALUE)) { + throw new ConfigurationException("You may only add a single Action " + + "annotation that has no value parameter."); + } + + actions.add(ann); + } + return actions; + } + + /** * Creates a single ActionConfig object. * * @param pkgCfg The package the action configuration instance will belong to. Modified: struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/annotation/Action.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/annotation/Action.java?rev=768826&r1=768825&r2=768826&view=diff ============================================================================== --- struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/annotation/Action.java (original) +++ struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/annotation/Action.java Sun Apr 26 22:58:17 2009 @@ -52,7 +52,7 @@ * </pre> * <!-- END SNIPPET: javadoc --> */ -...@target({ElementType.METHOD}) +...@target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Action { String DEFAULT_VALUE = "DEFAULT_VALUE"; Modified: struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/annotation/Actions.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/annotation/Actions.java?rev=768826&r1=768825&r2=768826&view=diff ============================================================================== --- struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/annotation/Actions.java (original) +++ struts/struts2/trunk/plugins/convention/src/main/java/org/apache/struts2/convention/annotation/Actions.java Sun Apr 26 22:58:17 2009 @@ -33,7 +33,7 @@ * </p> * <!-- END SNIPPET: javadoc --> */ -...@target(ElementType.METHOD) +...@target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Actions { Action[] value() default {}; Modified: struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/PackageBasedActionConfigBuilderTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/PackageBasedActionConfigBuilderTest.java?rev=768826&r1=768825&r2=768826&view=diff ============================================================================== --- struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/PackageBasedActionConfigBuilderTest.java (original) +++ struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/PackageBasedActionConfigBuilderTest.java Sun Apr 26 22:58:17 2009 @@ -35,11 +35,7 @@ import org.apache.struts2.convention.actions.NoAnnotationAction; import org.apache.struts2.convention.actions.Skip; import org.apache.struts2.convention.actions.chain.ChainedAction; -import org.apache.struts2.convention.actions.action.ActionNameAction; -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.action.TestExtends; +import org.apache.struts2.convention.actions.action.*; import org.apache.struts2.convention.actions.defaultinterceptor.SingleActionNameAction2; import org.apache.struts2.convention.actions.exception.ExceptionsActionLevelAction; import org.apache.struts2.convention.actions.exception.ExceptionsMethodLevelAction; @@ -194,6 +190,17 @@ expect(resultMapBuilder.build(TestAction.class, null, "test", actionPkg)).andReturn(results); expect(resultMapBuilder.build(TestExtends.class, null, "test-extends", actionPkg)).andReturn(results); + Actions classLevelActions = ClassLevelAnnotationsAction.class.getAnnotation(Actions.class); + expect(resultMapBuilder.build(ClassLevelAnnotationsAction.class, classLevelActions.value()[0], "class1", actionPkg)).andReturn(results); + expect(resultMapBuilder.build(ClassLevelAnnotationsAction.class, classLevelActions.value()[1], "class2", actionPkg)).andReturn(results); + + Actions classLevelActionsDefaultMethod = ClassLevelAnnotationsDefaultMethodAction.class.getAnnotation(Actions.class); + expect(resultMapBuilder.build(ClassLevelAnnotationsDefaultMethodAction.class, classLevelActionsDefaultMethod.value()[0], "class3", actionPkg)).andReturn(results); + expect(resultMapBuilder.build(ClassLevelAnnotationsDefaultMethodAction.class, classLevelActionsDefaultMethod.value()[1], "class4", actionPkg)).andReturn(results); + + expect(resultMapBuilder.build(ClassLevelAnnotationAction.class, ClassLevelAnnotationAction.class.getAnnotation(Action.class), "class5", actionPkg)).andReturn(results); + expect(resultMapBuilder.build(ClassLevelAnnotationDefaultMethodAction.class, ClassLevelAnnotationDefaultMethodAction.class.getAnnotation(Action.class), "class6", actionPkg)).andReturn(results); + /* org.apache.struts2.convention.actions.idx */ /* org.apache.struts2.convention.actions.idx.idx2 */ expect(resultMapBuilder.build(org.apache.struts2.convention.actions.idx.Index.class, null, "index", idxPkg)).andReturn(results); @@ -314,7 +321,7 @@ /* org.apache.struts2.convention.actions.action */ PackageConfig pkgConfig = configuration.getPackageConfig("org.apache.struts2.convention.actions.action#struts-default#/action"); assertNotNull(pkgConfig); - assertEquals(7, pkgConfig.getActionConfigs().size()); + assertEquals(13, pkgConfig.getActionConfigs().size()); verifyActionConfig(pkgConfig, "action1", ActionNameAction.class, "run1", pkgConfig.getName()); verifyActionConfig(pkgConfig, "action2", ActionNameAction.class, "run2", pkgConfig.getName()); verifyActionConfig(pkgConfig, "actions1", ActionNamesAction.class, "run", pkgConfig.getName()); @@ -323,6 +330,13 @@ verifyActionConfig(pkgConfig, "test", TestAction.class, "execute", pkgConfig.getName()); verifyActionConfig(pkgConfig, "test-extends", TestExtends.class, "execute", pkgConfig.getName()); + verifyActionConfig(pkgConfig, "class1", ClassLevelAnnotationsAction.class, null, pkgConfig.getName()); + verifyActionConfig(pkgConfig, "class2", ClassLevelAnnotationsAction.class, null, pkgConfig.getName()); + verifyActionConfig(pkgConfig, "class3", ClassLevelAnnotationsDefaultMethodAction.class, "execute", pkgConfig.getName()); + verifyActionConfig(pkgConfig, "class4", ClassLevelAnnotationsDefaultMethodAction.class, "execute", pkgConfig.getName()); + verifyActionConfig(pkgConfig, "class5", ClassLevelAnnotationAction.class, null, pkgConfig.getName()); + verifyActionConfig(pkgConfig, "class6", ClassLevelAnnotationDefaultMethodAction.class, "execute", pkgConfig.getName()); + /* org.apache.struts2.convention.actions.namespace3 */ //action on namespace1 (action level) pkgConfig = configuration.getPackageConfig("org.apache.struts2.convention.actions.namespace3#struts-default#/namespaces1"); Added: struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationAction.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationAction.java?rev=768826&view=auto ============================================================================== --- struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationAction.java (added) +++ struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationAction.java Sun Apr 26 22:58:17 2009 @@ -0,0 +1,27 @@ +/* + * $Id: ActionNamesAction.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.action; + +import org.apache.struts2.convention.annotation.Action; + +...@action("class5") +public class ClassLevelAnnotationAction { +} Added: struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationDefaultMethodAction.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationDefaultMethodAction.java?rev=768826&view=auto ============================================================================== --- struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationDefaultMethodAction.java (added) +++ struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationDefaultMethodAction.java Sun Apr 26 22:58:17 2009 @@ -0,0 +1,30 @@ +/* + * $Id: ActionNamesAction.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.action; + +import org.apache.struts2.convention.annotation.Action; + +...@action("class6") +public class ClassLevelAnnotationDefaultMethodAction { + public String execute() { + return "boo"; + } +} Added: struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationsAction.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationsAction.java?rev=768826&view=auto ============================================================================== --- struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationsAction.java (added) +++ struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationsAction.java Sun Apr 26 22:58:17 2009 @@ -0,0 +1,32 @@ +/* + * $Id: ActionNamesAction.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.action; + +import org.apache.struts2.convention.annotation.Actions; +import org.apache.struts2.convention.annotation.Action; + +...@actions({ + @Action("class1"), + @Action("class2") +}) +public class ClassLevelAnnotationsAction { + +} Added: struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationsDefaultMethodAction.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationsDefaultMethodAction.java?rev=768826&view=auto ============================================================================== --- struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationsDefaultMethodAction.java (added) +++ struts/struts2/trunk/plugins/convention/src/test/java/org/apache/struts2/convention/actions/action/ClassLevelAnnotationsDefaultMethodAction.java Sun Apr 26 22:58:17 2009 @@ -0,0 +1,34 @@ +/* + * $Id: ActionNamesAction.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.action; + +import org.apache.struts2.convention.annotation.Actions; +import org.apache.struts2.convention.annotation.Action; + +...@actions({ + @Action("class3"), + @Action("class4") +}) +public class ClassLevelAnnotationsDefaultMethodAction { + public String execute() { + return "boo"; + } +}