View Javadoc

1   /*
2    * $Id: RestActionInvocation.java 727100 2008-12-16 17:47:24Z musachy $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package org.apache.struts2.rest;
23  
24  import com.opensymphony.xwork2.ActionInvocation;
25  import com.opensymphony.xwork2.DefaultActionInvocation;
26  import com.opensymphony.xwork2.Result;
27  import com.opensymphony.xwork2.UnknownHandlerManager;
28  import com.opensymphony.xwork2.config.entities.ActionConfig;
29  import com.opensymphony.xwork2.inject.Inject;
30  import com.opensymphony.xwork2.util.logging.Logger;
31  import com.opensymphony.xwork2.util.logging.LoggerFactory;
32  import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
33  
34  import java.io.IOException;
35  import java.lang.reflect.InvocationTargetException;
36  import java.lang.reflect.Method;
37  import java.util.Map;
38  
39  
40  /***
41   * Extends the usual {@link ActionInvocation} to add support for processing the object returned
42   * from the action execution.  This allows us to support methods that return {@link HttpHeaders}
43   * as well as apply content type-specific operations to the result.
44   */
45  public class RestActionInvocation extends DefaultActionInvocation {
46      
47      private static final long serialVersionUID = 3485701178946428716L;
48  
49      private static final Logger LOG = LoggerFactory.getLogger(RestActionInvocation.class);
50      
51      private ContentTypeHandlerManager handlerSelector;
52  
53      protected RestActionInvocation(Map extraContext, boolean pushAction) {
54          super(extraContext, pushAction);
55      }
56  
57      @Inject
58      public void setMimeTypeHandlerSelector(ContentTypeHandlerManager sel) {
59          this.handlerSelector = sel;
60      }
61      
62      protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
63          String methodName = proxy.getMethod();
64  
65          if (LOG.isDebugEnabled()) {
66              LOG.debug("Executing action method = " + actionConfig.getMethodName());
67          }
68  
69          String timerKey = "invokeAction: "+proxy.getActionName();
70          try {
71              UtilTimerStack.push(timerKey);
72              
73              boolean methodCalled = false;
74              Object methodResult = null;
75              Method method = null;
76              try {
77                  method = getAction().getClass().getMethod(methodName, new Class[0]);
78              } catch (NoSuchMethodException e) {
79                  // hmm -- OK, try doXxx instead
80                  try {
81                      String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
82                      method = getAction().getClass().getMethod(altMethodName, new Class[0]);
83                  } catch (NoSuchMethodException e1) {
84                      // well, give the unknown handler a shot
85                      if (unknownHandlerManager.hasUnknownHandlers()) {
86                          try {
87                              methodResult = unknownHandlerManager.handleUnknownMethod(action, methodName);
88                              methodCalled = true;
89                          } catch (NoSuchMethodException e2) {
90                              // throw the original one
91                              throw e;
92                          }
93                      } else {
94                          throw e;
95                      }
96                  }
97              }
98              
99              if (!methodCalled) {
100                 methodResult = method.invoke(action, new Object[0]);
101             }
102             
103             return processResult(actionConfig, methodResult);
104         } catch (NoSuchMethodException e) {
105             throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");
106         } catch (InvocationTargetException e) {
107             // We try to return the source exception.
108             Throwable t = e.getTargetException();
109 
110             if (actionEventListener != null) {
111                 String result = actionEventListener.handleException(t, getStack());
112                 if (result != null) {
113                     return result;
114                 }
115             }
116             if (t instanceof Exception) {
117                 throw(Exception) t;
118             } else {
119                 throw e;
120             }
121         } finally {
122             UtilTimerStack.pop(timerKey);
123         }
124     }
125 
126     protected String processResult(ActionConfig actionConfig, Object methodResult) throws IOException {
127         if (methodResult instanceof Result) {
128             this.explicitResult = (Result) methodResult;
129             // Wire the result automatically
130             container.inject(explicitResult);
131             return null;
132         } else if (methodResult != null) {
133             resultCode = handlerSelector.handleResult(actionConfig, methodResult, action);
134         }
135         return resultCode;
136     }
137 
138 }