1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.annotations;
20
21 import java.lang.reflect.Field;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Modifier;
24 import java.util.Arrays;
25 import java.util.List;
26 import java.util.Locale;
27
28 import javax.annotation.Resource;
29 import javax.naming.InitialContext;
30 import javax.naming.NameNotFoundException;
31 import javax.naming.NamingException;
32
33 import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
34 import org.eclipse.jetty.plus.annotation.Injection;
35 import org.eclipse.jetty.plus.annotation.InjectionCollection;
36 import org.eclipse.jetty.util.log.Log;
37 import org.eclipse.jetty.util.log.Logger;
38 import org.eclipse.jetty.webapp.MetaData;
39 import org.eclipse.jetty.webapp.WebAppContext;
40
41 public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationHandler
42 {
43 private static final Logger LOG = Log.getLogger(ResourceAnnotationHandler.class);
44
45 protected static final List<Class<?>> ENV_ENTRY_TYPES =
46 Arrays.asList(new Class[] {String.class, Character.class, Integer.class, Boolean.class, Double.class, Byte.class, Short.class, Long.class, Float.class});
47
48
49 protected WebAppContext _context;
50
51
52 public ResourceAnnotationHandler (WebAppContext wac)
53 {
54 super(true);
55 _context = wac;
56 }
57
58
59
60
61
62
63
64 public void doHandle(Class<?> clazz)
65 {
66 if (supportsResourceInjection(clazz))
67 {
68 handleClass(clazz);
69
70 Method[] methods = clazz.getDeclaredMethods();
71 for (int i=0; i<methods.length; i++)
72 handleMethod(clazz, methods[i]);
73 Field[] fields = clazz.getDeclaredFields();
74
75 for (int i=0; i<fields.length; i++)
76 handleField(clazz, fields[i]);
77 }
78 }
79
80 public void handleClass (Class<?> clazz)
81 {
82 Resource resource = (Resource)clazz.getAnnotation(Resource.class);
83 if (resource != null)
84 {
85 String name = resource.name();
86 String mappedName = resource.mappedName();
87
88 if (name==null || name.trim().equals(""))
89 throw new IllegalStateException ("Class level Resource annotations must contain a name (Common Annotations Spec Section 2.3)");
90
91 try
92 {
93 if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context, name,mappedName))
94 if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context.getServer(), name,mappedName))
95 throw new IllegalStateException("No resource at "+(mappedName==null?name:mappedName));
96 }
97 catch (NamingException e)
98 {
99 LOG.warn(e);
100 }
101 }
102 }
103
104 public void handleField(Class<?> clazz, Field field)
105 {
106 Resource resource = (Resource)field.getAnnotation(Resource.class);
107 if (resource != null)
108 {
109
110 if (Modifier.isStatic(field.getModifiers()))
111 {
112 LOG.warn("Skipping Resource annotation on "+clazz.getName()+"."+field.getName()+": cannot be static");
113 return;
114 }
115
116
117 if (Modifier.isFinal(field.getModifiers()))
118 {
119 LOG.warn("Skipping Resource annotation on "+clazz.getName()+"."+field.getName()+": cannot be final");
120 return;
121 }
122
123
124 String name = clazz.getCanonicalName()+"/"+field.getName();
125
126
127 name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name);
128 String mappedName = (resource.mappedName()!=null && !resource.mappedName().trim().equals("")?resource.mappedName():null);
129
130 Class<?> type = field.getType();
131
132
133
134
135 MetaData metaData = _context.getMetaData();
136 if (metaData.getOriginDescriptor("resource-ref."+name+".injection") != null)
137 {
138
139
140 return;
141 }
142
143
144
145 InjectionCollection injections = (InjectionCollection)_context.getAttribute(InjectionCollection.INJECTION_COLLECTION);
146 if (injections == null)
147 {
148 injections = new InjectionCollection();
149 _context.setAttribute(InjectionCollection.INJECTION_COLLECTION, injections);
150 }
151 Injection injection = injections.getInjection(name, clazz, field);
152 if (injection == null)
153 {
154
155 try
156 {
157 boolean bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context, name, mappedName);
158 if (!bound)
159 bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context.getServer(), name, mappedName);
160 if (!bound)
161 bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(null, name, mappedName);
162 if (!bound)
163 {
164
165 try
166 {
167 InitialContext ic = new InitialContext();
168 String nameInEnvironment = (mappedName!=null?mappedName:name);
169 ic.lookup("java:comp/env/"+nameInEnvironment);
170 bound = true;
171 }
172 catch (NameNotFoundException e)
173 {
174 bound = false;
175 }
176 }
177
178 if (bound)
179 {
180 LOG.debug("Bound "+(mappedName==null?name:mappedName) + " as "+ name);
181
182 injection = new Injection();
183 injection.setTarget(clazz, field, type);
184 injection.setJndiName(name);
185 injection.setMappingName(mappedName);
186 injections.add(injection);
187
188
189 metaData.setOrigin("resource-ref."+name+".injection",resource,clazz);
190 }
191 else if (!isEnvEntryType(type))
192 {
193
194
195
196
197 throw new IllegalStateException("No resource at "+(mappedName==null?name:mappedName));
198 }
199 }
200 catch (NamingException e)
201 {
202
203
204
205 if (!isEnvEntryType(type))
206 throw new IllegalStateException(e);
207 }
208 }
209 }
210 }
211
212
213
214
215
216
217
218
219
220
221
222 public void handleMethod(Class<?> clazz, Method method)
223 {
224
225 Resource resource = (Resource)method.getAnnotation(Resource.class);
226 if (resource != null)
227 {
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246 if (Modifier.isStatic(method.getModifiers()))
247 {
248 LOG.warn("Skipping Resource annotation on "+clazz.getName()+"."+method.getName()+": cannot be static");
249 return;
250 }
251
252
253
254 if (!method.getName().startsWith("set"))
255 {
256 LOG.warn("Skipping Resource annotation on "+clazz.getName()+"."+method.getName()+": invalid java bean, does not start with 'set'");
257 return;
258 }
259
260 if (method.getParameterTypes().length != 1)
261 {
262 LOG.warn("Skipping Resource annotation on "+clazz.getName()+"."+method.getName()+": invalid java bean, not single argument to method");
263 return;
264 }
265
266 if (Void.TYPE != method.getReturnType())
267 {
268 LOG.warn("Skipping Resource annotation on "+clazz.getName()+"."+method.getName()+": invalid java bean, not void");
269 return;
270 }
271
272
273
274 String name = method.getName().substring(3);
275 name = name.substring(0,1).toLowerCase(Locale.ENGLISH)+name.substring(1);
276 name = clazz.getCanonicalName()+"/"+name;
277
278 name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name);
279 String mappedName = (resource.mappedName()!=null && !resource.mappedName().trim().equals("")?resource.mappedName():null);
280 Class<?> paramType = method.getParameterTypes()[0];
281
282 Class<?> resourceType = resource.type();
283
284
285
286
287 MetaData metaData = _context.getMetaData();
288 if (metaData.getOriginDescriptor("resource-ref."+name+".injection") != null)
289 {
290
291
292 return;
293 }
294
295
296 InjectionCollection injections = (InjectionCollection)_context.getAttribute(InjectionCollection.INJECTION_COLLECTION);
297 if (injections == null)
298 {
299 injections = new InjectionCollection();
300 _context.setAttribute(InjectionCollection.INJECTION_COLLECTION, injections);
301 }
302 Injection injection = injections.getInjection(name, clazz, method, paramType);
303 if (injection == null)
304 {
305 try
306 {
307
308
309 boolean bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context, name, mappedName);
310
311
312 if (!bound)
313 bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context.getServer(), name, mappedName);
314
315
316 if (!bound)
317 bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(null, name, mappedName);
318
319
320
321 if (!bound)
322 {
323 try
324 {
325 InitialContext ic = new InitialContext();
326 String nameInEnvironment = (mappedName!=null?mappedName:name);
327 ic.lookup("java:comp/env/"+nameInEnvironment);
328 bound = true;
329 }
330 catch (NameNotFoundException e)
331 {
332 bound = false;
333 }
334 }
335
336 if (bound)
337 {
338 LOG.debug("Bound "+(mappedName==null?name:mappedName) + " as "+ name);
339
340 injection = new Injection();
341 injection.setTarget(clazz, method,paramType,resourceType);
342 injection.setJndiName(name);
343 injection.setMappingName(mappedName);
344 injections.add(injection);
345
346 metaData.setOrigin("resource-ref."+name+".injection",resource,clazz);
347 }
348 else if (!isEnvEntryType(paramType))
349 {
350
351
352
353
354 throw new IllegalStateException("No resource at "+(mappedName==null?name:mappedName));
355 }
356 }
357 catch (NamingException e)
358 {
359
360
361
362 if (!isEnvEntryType(paramType))
363 throw new IllegalStateException(e);
364 }
365 }
366
367 }
368 }
369
370
371
372
373
374
375
376 public boolean supportsResourceInjection (Class<?> c)
377 {
378 if (javax.servlet.Servlet.class.isAssignableFrom(c) ||
379 javax.servlet.Filter.class.isAssignableFrom(c) ||
380 javax.servlet.ServletContextListener.class.isAssignableFrom(c) ||
381 javax.servlet.ServletContextAttributeListener.class.isAssignableFrom(c) ||
382 javax.servlet.ServletRequestListener.class.isAssignableFrom(c) ||
383 javax.servlet.ServletRequestAttributeListener.class.isAssignableFrom(c) ||
384 javax.servlet.http.HttpSessionListener.class.isAssignableFrom(c) ||
385 javax.servlet.http.HttpSessionAttributeListener.class.isAssignableFrom(c) ||
386 javax.servlet.http.HttpSessionIdListener.class.isAssignableFrom(c) ||
387 javax.servlet.AsyncListener.class.isAssignableFrom(c) ||
388 javax.servlet.http.HttpUpgradeHandler.class.isAssignableFrom(c))
389 return true;
390
391 return false;
392 }
393
394
395
396
397
398
399
400
401 public boolean isEnvEntryType (Class<?> clazz)
402 {
403 return ENV_ENTRY_TYPES.contains(clazz);
404 }
405 }