1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.struts2.rest;
23
24 import com.opensymphony.xwork2.ActionContext;
25 import com.opensymphony.xwork2.ActionEventListener;
26 import com.opensymphony.xwork2.ActionInvocation;
27 import com.opensymphony.xwork2.ActionProxy;
28 import com.opensymphony.xwork2.DefaultActionInvocation;
29 import com.opensymphony.xwork2.ModelDriven;
30 import com.opensymphony.xwork2.ObjectFactory;
31 import com.opensymphony.xwork2.Result;
32 import com.opensymphony.xwork2.UnknownHandler;
33 import com.opensymphony.xwork2.config.ConfigurationException;
34 import com.opensymphony.xwork2.config.entities.ActionConfig;
35 import com.opensymphony.xwork2.config.entities.InterceptorMapping;
36 import com.opensymphony.xwork2.config.entities.ResultConfig;
37 import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
38 import com.opensymphony.xwork2.inject.Container;
39 import com.opensymphony.xwork2.inject.Inject;
40 import com.opensymphony.xwork2.interceptor.PreResultListener;
41 import com.opensymphony.xwork2.util.ValueStack;
42 import com.opensymphony.xwork2.util.ValueStackFactory;
43 import com.opensymphony.xwork2.util.logging.LoggerFactory;
44 import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
45 import com.opensymphony.xwork2.util.logging.Logger;
46
47 import org.apache.struts2.ServletActionContext;
48 import org.apache.struts2.rest.handler.ContentTypeHandler;
49
50 import java.io.ByteArrayOutputStream;
51 import java.io.IOException;
52 import java.lang.reflect.InvocationTargetException;
53 import java.lang.reflect.Method;
54 import java.lang.reflect.Proxy;
55 import java.util.ArrayList;
56 import java.util.Collections;
57 import java.util.HashMap;
58 import java.util.HashSet;
59 import java.util.Iterator;
60 import java.util.LinkedHashMap;
61 import java.util.List;
62 import java.util.Map;
63 import java.util.Set;
64
65 import javax.servlet.http.HttpServletRequest;
66 import javax.servlet.http.HttpServletResponse;
67
68
69 /***
70 * Extends the usual {@link ActionInvocation} to add support for processing the object returned
71 * from the action execution. This allows us to support methods that return {@link HttpHeaders}
72 * as well as apply content type-specific operations to the result.
73 */
74 public class RestActionInvocation extends DefaultActionInvocation {
75
76 private static final long serialVersionUID = 3485701178946428716L;
77
78 private static final Logger LOG = LoggerFactory.getLogger(RestActionInvocation.class);
79
80 private ContentTypeHandlerManager handlerSelector;
81
82 protected RestActionInvocation(Map extraContext, boolean pushAction) {
83 super(extraContext, pushAction);
84 }
85
86 @Inject
87 public void setMimeTypeHandlerSelector(ContentTypeHandlerManager sel) {
88 this.handlerSelector = sel;
89 }
90
91 protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
92 String methodName = proxy.getMethod();
93
94 if (LOG.isDebugEnabled()) {
95 LOG.debug("Executing action method = " + actionConfig.getMethodName());
96 }
97
98 String timerKey = "invokeAction: "+proxy.getActionName();
99 try {
100 UtilTimerStack.push(timerKey);
101
102 boolean methodCalled = false;
103 Object methodResult = null;
104 Method method = null;
105 try {
106 method = getAction().getClass().getMethod(methodName, new Class[0]);
107 } catch (NoSuchMethodException e) {
108
109 try {
110 String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
111 method = getAction().getClass().getMethod(altMethodName, new Class[0]);
112 } catch (NoSuchMethodException e1) {
113
114 if (unknownHandler != null) {
115 try {
116 methodResult = unknownHandler.handleUnknownActionMethod(action, methodName);
117 methodCalled = true;
118 } catch (NoSuchMethodException e2) {
119
120 throw e;
121 }
122 } else {
123 throw e;
124 }
125 }
126 }
127
128 if (!methodCalled) {
129 methodResult = method.invoke(action, new Object[0]);
130 }
131
132 return processResult(actionConfig, methodResult);
133 } catch (NoSuchMethodException e) {
134 throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");
135 } catch (InvocationTargetException e) {
136
137 Throwable t = e.getTargetException();
138
139 if (actionEventListener != null) {
140 String result = actionEventListener.handleException(t, getStack());
141 if (result != null) {
142 return result;
143 }
144 }
145 if (t instanceof Exception) {
146 throw(Exception) t;
147 } else {
148 throw e;
149 }
150 } finally {
151 UtilTimerStack.pop(timerKey);
152 }
153 }
154
155 protected String processResult(ActionConfig actionConfig, Object methodResult) throws IOException {
156 if (methodResult instanceof Result) {
157 this.explicitResult = (Result) methodResult;
158 return null;
159 } else if (methodResult != null) {
160 resultCode = handlerSelector.handleResult(actionConfig, methodResult, action);
161 }
162 return resultCode;
163 }
164
165 }