1 package com.atlassian.plugins.rest.common.interceptor.impl;
2
3 import com.atlassian.plugins.rest.common.interceptor.MethodInvocation;
4 import com.atlassian.plugins.rest.common.interceptor.ResourceInterceptor;
5 import com.atlassian.plugins.rest.common.interceptor.impl.DefaultMethodInvocation;
6 import com.atlassian.plugins.rest.common.interceptor.impl.InterceptorChainBuilder;
7 import com.sun.jersey.api.core.HttpContext;
8 import com.sun.jersey.api.model.AbstractResourceMethod;
9 import com.sun.jersey.server.impl.ResponseBuilderImpl;
10 import com.sun.jersey.server.impl.inject.InjectableValuesProvider;
11 import com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider;
12 import com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher;
13 import com.sun.jersey.server.impl.model.method.dispatch.ResourceMethodDispatchProvider;
14 import com.sun.jersey.spi.dispatch.RequestDispatcher;
15
16 import javax.ws.rs.core.GenericEntity;
17 import javax.ws.rs.core.Response;
18 import java.lang.reflect.InvocationTargetException;
19 import java.lang.reflect.Type;
20 import java.util.ArrayList;
21 import java.util.List;
22
23
24
25
26
27
28 class DispatchProviderHelper
29 {
30 private final InterceptorChainBuilder interceptorChainBuilder;
31
32 public DispatchProviderHelper(InterceptorChainBuilder interceptorChainBuilder)
33 {
34 this.interceptorChainBuilder = interceptorChainBuilder;
35 }
36
37 public RequestDispatcher create(AbstractResourceMethod abstractResourceMethod, InjectableValuesProvider pp)
38 {
39 if (pp == null)
40 {
41 return null;
42 }
43
44 final List<ResourceInterceptor> interceptors = interceptorChainBuilder.getResourceInterceptorsForMethod(abstractResourceMethod.getMethod());
45
46
47
48
49
50 boolean requireReturnOfRepresentation =
51 "GET".equals(abstractResourceMethod.getHttpMethod());
52
53 Class<?> returnType = abstractResourceMethod.getMethod().getReturnType();
54 if (Response.class.isAssignableFrom(returnType))
55 {
56 return new ResponseOutInvoker(abstractResourceMethod, pp, interceptors);
57 }
58 else if (returnType != void.class)
59 {
60 if (returnType == Object.class || GenericEntity.class.isAssignableFrom(returnType))
61 {
62 return new ObjectOutInvoker(abstractResourceMethod, pp, interceptors);
63 }
64 else
65 {
66 return new TypeOutInvoker(abstractResourceMethod, pp, interceptors);
67 }
68 }
69 else if (requireReturnOfRepresentation)
70 {
71 return null;
72 }
73 else
74 {
75 return new VoidOutInvoker(abstractResourceMethod, pp, interceptors);
76 }
77 }
78
79 private static void invokeMethodWithInterceptors(List<ResourceInterceptor> originalInterceptors,
80 AbstractResourceMethod method,
81 Object resource,
82 HttpContext httpContext,
83 Object[] params,
84 final MethodInvoker methodInvocation) throws IllegalAccessException, InvocationTargetException
85 {
86 ResourceInterceptor lastInterceptor = new ResourceInterceptor()
87 {
88 public void intercept(MethodInvocation invocation) throws IllegalAccessException, InvocationTargetException
89 {
90 methodInvocation.invoke();
91 }
92 };
93
94 List<ResourceInterceptor> interceptors = new ArrayList<ResourceInterceptor>(originalInterceptors);
95 interceptors.add(lastInterceptor);
96
97 MethodInvocation inv = new DefaultMethodInvocation(resource, method, httpContext, interceptors, params);
98 inv.invoke();
99 }
100
101 private static interface MethodInvoker
102 {
103 void invoke() throws IllegalAccessException, InvocationTargetException;
104 }
105
106
107 private static abstract class EntityParamInInvoker extends ResourceJavaMethodDispatcher
108 {
109 private final InjectableValuesProvider pp;
110 final AbstractResourceMethod abstractResourceMethod;
111 final List<ResourceInterceptor> interceptors;
112
113 EntityParamInInvoker(AbstractResourceMethod abstractResourceMethod,
114 InjectableValuesProvider pp,
115 List<ResourceInterceptor> interceptors)
116 {
117 super(abstractResourceMethod);
118 this.pp = pp;
119 this.abstractResourceMethod = abstractResourceMethod;
120 this.interceptors = interceptors;
121 }
122
123 final Object[] getParams(HttpContext context)
124 {
125 return pp.getInjectableValues(context);
126 }
127
128 }
129
130 private static final class VoidOutInvoker extends EntityParamInInvoker
131 {
132
133
134 VoidOutInvoker(AbstractResourceMethod abstractResourceMethod,
135 InjectableValuesProvider pp,
136 List<ResourceInterceptor> interceptors)
137 {
138 super(abstractResourceMethod, pp, interceptors);
139 }
140
141 public void _dispatch(final Object resource, HttpContext context)
142 throws IllegalAccessException, InvocationTargetException
143 {
144 final Object[] params = getParams(context);
145 invokeMethodWithInterceptors(interceptors, abstractResourceMethod, resource, context, params, new MethodInvoker()
146 {
147 public void invoke() throws IllegalAccessException, InvocationTargetException
148 {
149 method.invoke(resource, params);
150 }
151 });
152 }
153 }
154
155 private static final class TypeOutInvoker extends EntityParamInInvoker
156 {
157 private final Type t;
158
159 TypeOutInvoker(AbstractResourceMethod abstractResourceMethod,
160 InjectableValuesProvider pp,
161 List<ResourceInterceptor> interceptors)
162 {
163 super(abstractResourceMethod, pp, interceptors);
164 this.t = abstractResourceMethod.getMethod().getGenericReturnType();
165 }
166
167 public void _dispatch(final Object resource, final HttpContext context)
168 throws IllegalAccessException, InvocationTargetException
169 {
170 final Object[] params = getParams(context);
171
172 invokeMethodWithInterceptors(interceptors, abstractResourceMethod, resource, context, params, new MethodInvoker()
173 {
174 public void invoke() throws IllegalAccessException, InvocationTargetException
175 {
176 Object o = method.invoke(resource, params);
177 if (o != null)
178 {
179 Response r = new ResponseBuilderImpl().
180 entityWithType(o, t).status(200).build();
181 context.getResponse().setResponse(r);
182 }
183 }
184 });
185 }
186 }
187
188 private static final class ResponseOutInvoker extends EntityParamInInvoker
189 {
190 ResponseOutInvoker(AbstractResourceMethod abstractResourceMethod,
191 InjectableValuesProvider pp,
192 List<ResourceInterceptor> interceptors)
193 {
194 super(abstractResourceMethod, pp, interceptors);
195 }
196
197 public void _dispatch(final Object resource, final HttpContext context)
198 throws IllegalAccessException, InvocationTargetException
199 {
200 final Object[] params = getParams(context);
201
202 invokeMethodWithInterceptors(interceptors, abstractResourceMethod, resource, context, params, new MethodInvoker()
203 {
204 public void invoke() throws IllegalAccessException, InvocationTargetException
205 {
206 Response r = (Response) method.invoke(resource, params);
207 if (r != null)
208 {
209 context.getResponse().setResponse(r);
210 }
211 }
212 });
213
214 }
215 }
216
217 private static final class ObjectOutInvoker extends EntityParamInInvoker
218 {
219 ObjectOutInvoker(AbstractResourceMethod abstractResourceMethod,
220 InjectableValuesProvider pp,
221 List<ResourceInterceptor> interceptors)
222 {
223 super(abstractResourceMethod, pp, interceptors);
224 }
225
226 public void _dispatch(final Object resource, final HttpContext context)
227 throws IllegalAccessException, InvocationTargetException
228 {
229 final Object[] params = getParams(context);
230
231 invokeMethodWithInterceptors(interceptors, abstractResourceMethod, resource, context, params, new MethodInvoker()
232 {
233 public void invoke() throws IllegalAccessException, InvocationTargetException
234 {
235 Object o = method.invoke(resource, params);
236
237 if (o instanceof Response)
238 {
239 Response r = (Response) o;
240 context.getResponse().setResponse(r);
241 }
242 else if (o != null)
243 {
244 Response r = new ResponseBuilderImpl().status(200).entity(o).build();
245 context.getResponse().setResponse(r);
246 }
247 }
248 });
249
250
251 }
252 }
253 }