1 package com.atlassian.plugins.rest.common.interceptor.impl;
2
3 import java.lang.reflect.InvocationTargetException;
4 import java.lang.reflect.Type;
5 import java.util.ArrayList;
6 import java.util.List;
7
8 import javax.ws.rs.core.GenericEntity;
9 import javax.ws.rs.core.Response;
10
11 import com.atlassian.plugins.rest.common.interceptor.MethodInvocation;
12 import com.atlassian.plugins.rest.common.interceptor.ResourceInterceptor;
13 import com.sun.jersey.api.core.HttpContext;
14 import com.sun.jersey.api.model.AbstractResourceMethod;
15 import com.sun.jersey.core.spi.factory.ResponseBuilderImpl;
16 import com.sun.jersey.server.impl.inject.InjectableValuesProvider;
17 import com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher;
18 import com.sun.jersey.spi.container.JavaMethodInvokerFactory;
19 import com.sun.jersey.spi.dispatch.RequestDispatcher;
20
21
22
23
24
25
26
27
28
29
30 public class DispatchProviderHelper
31 {
32 private final InterceptorChainBuilder interceptorChainBuilder;
33
34 public DispatchProviderHelper(InterceptorChainBuilder interceptorChainBuilder)
35 {
36 this.interceptorChainBuilder = interceptorChainBuilder;
37 }
38
39 public RequestDispatcher create(AbstractResourceMethod abstractResourceMethod, InjectableValuesProvider pp)
40 {
41 if (pp == null)
42 {
43 return null;
44 }
45
46 final List<ResourceInterceptor> interceptors = interceptorChainBuilder.getResourceInterceptorsForMethod(abstractResourceMethod.getMethod());
47
48
49
50
51
52 boolean requireReturnOfRepresentation =
53 "GET".equals(abstractResourceMethod.getHttpMethod());
54
55 Class<?> returnType = abstractResourceMethod.getMethod().getReturnType();
56 if (Response.class.isAssignableFrom(returnType))
57 {
58 return new ResponseOutInvoker(abstractResourceMethod, pp, interceptors);
59 }
60 else if (returnType != void.class)
61 {
62 if (returnType == Object.class || GenericEntity.class.isAssignableFrom(returnType))
63 {
64 return new ObjectOutInvoker(abstractResourceMethod, pp, interceptors);
65 }
66 else
67 {
68 return new TypeOutInvoker(abstractResourceMethod, pp, interceptors);
69 }
70 }
71 else if (requireReturnOfRepresentation)
72 {
73 return null;
74 }
75 else
76 {
77 return new VoidOutInvoker(abstractResourceMethod, pp, interceptors);
78 }
79 }
80
81 private static void invokeMethodWithInterceptors(List<ResourceInterceptor> originalInterceptors,
82 AbstractResourceMethod method,
83 Object resource,
84 HttpContext httpContext,
85 Object[] params,
86 final MethodInvoker methodInvocation) throws IllegalAccessException, InvocationTargetException
87 {
88 ResourceInterceptor lastInterceptor = new ResourceInterceptor()
89 {
90 public void intercept(MethodInvocation invocation) throws IllegalAccessException, InvocationTargetException
91 {
92 methodInvocation.invoke();
93 }
94 };
95
96 List<ResourceInterceptor> interceptors = new ArrayList<ResourceInterceptor>(originalInterceptors);
97 interceptors.add(lastInterceptor);
98
99 MethodInvocation inv = new DefaultMethodInvocation(resource, method, httpContext, interceptors, params);
100 inv.invoke();
101 }
102
103 private static interface MethodInvoker
104 {
105 void invoke() throws IllegalAccessException, InvocationTargetException;
106 }
107
108
109 private static abstract class EntityParamInInvoker extends ResourceJavaMethodDispatcher
110 {
111 private final InjectableValuesProvider pp;
112 final AbstractResourceMethod abstractResourceMethod;
113 final List<ResourceInterceptor> interceptors;
114
115 EntityParamInInvoker(AbstractResourceMethod abstractResourceMethod,
116 InjectableValuesProvider pp,
117 List<ResourceInterceptor> interceptors)
118 {
119 super(abstractResourceMethod, JavaMethodInvokerFactory.getDefault());
120 this.pp = pp;
121 this.abstractResourceMethod = abstractResourceMethod;
122 this.interceptors = interceptors;
123 }
124
125 final Object[] getParams(HttpContext context)
126 {
127 return pp.getInjectableValues(context);
128 }
129
130 }
131
132 private static final class VoidOutInvoker extends EntityParamInInvoker
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 }