1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.annotations;
15
16 import java.lang.reflect.Field;
17 import java.lang.reflect.Method;
18 import java.lang.reflect.Modifier;
19 import java.util.List;
20
21 import javax.annotation.Resource;
22 import javax.naming.InitialContext;
23 import javax.naming.NameNotFoundException;
24 import javax.naming.NamingException;
25
26 import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler;
27 import org.eclipse.jetty.annotations.AnnotationParser.Value;
28 import org.eclipse.jetty.plus.annotation.Injection;
29 import org.eclipse.jetty.plus.annotation.InjectionCollection;
30 import org.eclipse.jetty.util.IntrospectionUtil;
31 import org.eclipse.jetty.util.Loader;
32 import org.eclipse.jetty.util.log.Log;
33 import org.eclipse.jetty.webapp.WebAppContext;
34
35 public class ResourceAnnotationHandler implements AnnotationHandler
36 {
37 protected WebAppContext _wac;
38
39 public ResourceAnnotationHandler (WebAppContext wac)
40 {
41 _wac = wac;
42 }
43
44
45
46
47
48
49
50 public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
51 List<Value> values)
52 {
53 Class clazz = null;
54 try
55 {
56 clazz = Loader.loadClass(null, className);
57 }
58 catch (Exception e)
59 {
60 Log.warn(e);
61 }
62 if (!Util.isServletType(clazz))
63 {
64 Log.debug("Ignoring @Resource annotation on on-servlet type class "+clazz.getName());
65 return;
66 }
67
68
69 Resource resource = (Resource)clazz.getAnnotation(Resource.class);
70 if (resource != null)
71 {
72 String name = resource.name();
73 String mappedName = resource.mappedName();
74 Resource.AuthenticationType auth = resource.authenticationType();
75 Class type = resource.type();
76 boolean shareable = resource.shareable();
77
78 if (name==null || name.trim().equals(""))
79 throw new IllegalStateException ("Class level Resource annotations must contain a name (Common Annotations Spec Section 2.3)");
80
81 try
82 {
83
84 if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name,mappedName))
85 if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name,mappedName))
86 throw new IllegalStateException("No resource at "+(mappedName==null?name:mappedName));
87 }
88 catch (NamingException e)
89 {
90 Log.warn(e);
91 }
92 }
93 }
94
95 public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation,
96 List<Value> values)
97 {
98 InjectionCollection injections = (InjectionCollection)_wac.getAttribute(InjectionCollection.INJECTION_COLLECTION);
99 Class clazz = null;
100 try
101 {
102 clazz = Loader.loadClass(null, className);
103 Field f = clazz.getDeclaredField(fieldName);
104
105 if (!Util.isServletType(clazz))
106 {
107 Log.debug("Ignoring @Resource annotation on on-servlet type field "+fieldName);
108 return;
109 }
110 Resource resource = (Resource)f.getAnnotation(Resource.class);
111 if (resource == null)
112 return;
113
114
115 if (Modifier.isStatic(f.getModifiers()))
116 throw new IllegalStateException(f+" cannot be static");
117
118
119 if (Modifier.isFinal(f.getModifiers()))
120 throw new IllegalStateException(f+" cannot be final");
121
122
123 String name = f.getDeclaringClass().getCanonicalName()+"/"+f.getName();
124
125 name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name);
126
127
128 Class type = f.getType();
129
130 if ((resource.type() != null)
131 &&
132 !resource.type().equals(Object.class)
133 &&
134 (!IntrospectionUtil.isTypeCompatible(type, resource.type(), false)))
135 throw new IllegalStateException("@Resource incompatible type="+resource.type()+ " with field type ="+f.getType());
136
137
138 String mappedName = (resource.mappedName()!=null && !resource.mappedName().trim().equals("")?resource.mappedName():null);
139
140 Resource.AuthenticationType auth = resource.authenticationType();
141 boolean shareable = resource.shareable();
142
143 Injection webXmlInjection = injections.getInjection(f.getDeclaringClass(), f);
144 if (webXmlInjection == null)
145 {
146 try
147 {
148 boolean bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name, mappedName);
149 if (!bound)
150 bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name, mappedName);
151 if (!bound)
152 bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(null, name, mappedName);
153 if (!bound)
154 {
155
156 try
157 {
158 InitialContext ic = new InitialContext();
159 String nameInEnvironment = (mappedName!=null?mappedName:name);
160 ic.lookup("java:comp/env/"+nameInEnvironment);
161 bound = true;
162 }
163 catch (NameNotFoundException e)
164 {
165 bound = false;
166 }
167 }
168
169 if (bound)
170 {
171 Log.debug("Bound "+(mappedName==null?name:mappedName) + " as "+ name);
172
173 Injection injection = new Injection();
174 injection.setTargetClass(f.getDeclaringClass());
175 injection.setJndiName(name);
176 injection.setMappingName(mappedName);
177 injection.setTarget(f);
178 injections.add(injection);
179 }
180 else if (!Util.isEnvEntryType(type))
181 {
182
183
184
185
186 throw new IllegalStateException("No resource at "+(mappedName==null?name:mappedName));
187 }
188 }
189 catch (NamingException e)
190 {
191
192
193
194 if (!Util.isEnvEntryType(type))
195 throw new IllegalStateException(e);
196 }
197 }
198 else
199 {
200
201
202 Object val = webXmlInjection.lookupInjectedValue();
203 if (!IntrospectionUtil.isTypeCompatible(type, value.getClass(), false))
204 throw new IllegalStateException("Type of field="+type+" is not compatible with Resource type="+val.getClass());
205 }
206 }
207 catch (Exception e)
208 {
209 Log.warn(e);
210 }
211 }
212
213
214
215
216
217
218
219
220 public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation,
221 List<Value> values)
222 {
223 InjectionCollection injections = (InjectionCollection)_wac.getAttribute(InjectionCollection.INJECTION_COLLECTION);
224 Class clazz = null;
225 try
226 {
227 clazz = Loader.loadClass(null, className);
228
229 Class[] args = Util.convertTypes(params);
230 Method m = clazz.getDeclaredMethod(methodName, args);
231
232 if (!Util.isServletType(m.getDeclaringClass()))
233 {
234 Log.debug("Ignoring @Resource annotation on on-servlet type method "+m.getName());
235 return;
236 }
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254 Resource resource = (Resource)m.getAnnotation(Resource.class);
255 if (resource == null)
256 return;
257
258
259 if (Modifier.isStatic(m.getModifiers()))
260 throw new IllegalStateException(m+" cannot be static");
261
262
263
264 if (!IntrospectionUtil.isJavaBeanCompliantSetter(m))
265 throw new IllegalStateException(m+" is not a java bean compliant setter method");
266
267
268 String name = m.getName().substring(3);
269 name = name.substring(0,1).toLowerCase()+name.substring(1);
270 name = m.getDeclaringClass().getCanonicalName()+"/"+name;
271
272 name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name);
273
274 String mappedName = (resource.mappedName()!=null && !resource.mappedName().trim().equals("")?resource.mappedName():null);
275
276 Class type = m.getParameterTypes()[0];
277
278
279 Resource.AuthenticationType auth = resource.authenticationType();
280 boolean shareable = resource.shareable();
281
282
283 if ((resource.type() != null)
284 &&
285 !resource.type().equals(Object.class)
286 &&
287 (!IntrospectionUtil.isTypeCompatible(type, resource.type(), false)))
288 throw new IllegalStateException("@Resource incompatible type="+resource.type()+ " with method param="+type+ " for "+m);
289
290
291 Injection webXmlInjection = injections.getInjection(m.getDeclaringClass(), m);
292 if (webXmlInjection == null)
293 {
294 try
295 {
296
297
298 boolean bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name, mappedName);
299
300
301 if (!bound)
302 bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name, mappedName);
303
304
305 if (!bound)
306 bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(null, name, mappedName);
307
308
309
310 if (!bound)
311 {
312 try
313 {
314 InitialContext ic = new InitialContext();
315 String nameInEnvironment = (mappedName!=null?mappedName:name);
316 ic.lookup("java:comp/env/"+nameInEnvironment);
317 bound = true;
318 }
319 catch (NameNotFoundException e)
320 {
321 bound = false;
322 }
323 }
324
325 if (bound)
326 {
327 Log.debug("Bound "+(mappedName==null?name:mappedName) + " as "+ name);
328
329 Injection injection = new Injection();
330 injection.setTargetClass(m.getDeclaringClass());
331 injection.setJndiName(name);
332 injection.setMappingName(mappedName);
333 injection.setTarget(m);
334 injections.add(injection);
335 }
336 else if (!Util.isEnvEntryType(type))
337 {
338
339
340
341
342 throw new IllegalStateException("No resource at "+(mappedName==null?name:mappedName));
343 }
344 }
345 catch (NamingException e)
346 {
347
348
349
350 if (!Util.isEnvEntryType(type))
351 throw new IllegalStateException(e);
352 }
353 }
354 else
355 {
356
357
358
359 Object value = webXmlInjection.lookupInjectedValue();
360 if (!IntrospectionUtil.isTypeCompatible(type, value.getClass(), false))
361 throw new IllegalStateException("Type of field="+type+" is not compatible with Resource type="+value.getClass());
362 }
363 }
364 catch (Exception e)
365 {
366 Log.warn(e);
367 }
368 }
369 }