You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by mu...@apache.org on 2009/04/27 00:58:18 UTC

svn commit: r768826 - in /struts/struts2/trunk/plugins/convention/src: main/java/org/apache/struts2/convention/ main/java/org/apache/struts2/convention/annotation/ test/java/org/apache/struts2/convention/ test/java/org/apache/struts2/convention/actions...

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";
+   }
+}