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.net.URI;
22 import java.util.ArrayList;
23 import java.util.EventListener;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.ServiceLoader;
27 import java.util.StringTokenizer;
28
29 import javax.servlet.ServletContainerInitializer;
30 import javax.servlet.annotation.HandlesTypes;
31
32 import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
33 import org.eclipse.jetty.plus.annotation.ContainerInitializer;
34 import org.eclipse.jetty.util.ArrayUtil;
35 import org.eclipse.jetty.util.MultiMap;
36 import org.eclipse.jetty.util.log.Log;
37 import org.eclipse.jetty.util.log.Logger;
38 import org.eclipse.jetty.util.resource.Resource;
39 import org.eclipse.jetty.webapp.AbstractConfiguration;
40 import org.eclipse.jetty.webapp.FragmentDescriptor;
41 import org.eclipse.jetty.webapp.MetaDataComplete;
42 import org.eclipse.jetty.webapp.WebAppContext;
43 import org.eclipse.jetty.webapp.WebDescriptor;
44
45
46
47
48
49
50 public class AnnotationConfiguration extends AbstractConfiguration
51 {
52 private static final Logger LOG = Log.getLogger(AnnotationConfiguration.class);
53 public static final String CLASS_INHERITANCE_MAP = "org.eclipse.jetty.classInheritanceMap";
54 public static final String CONTAINER_INITIALIZERS = "org.eclipse.jetty.containerInitializers";
55 public static final String CONTAINER_INITIALIZER_LISTENER = "org.eclipse.jetty.containerInitializerListener";
56
57
58 protected List<DiscoverableAnnotationHandler> _discoverableAnnotationHandlers = new ArrayList<DiscoverableAnnotationHandler>();
59 protected ClassInheritanceHandler _classInheritanceHandler;
60 protected List<ContainerInitializerAnnotationHandler> _containerInitializerAnnotationHandlers = new ArrayList<ContainerInitializerAnnotationHandler>();
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 public class WebAppClassNameResolver implements ClassNameResolver
76 {
77 private WebAppContext _context;
78
79 public WebAppClassNameResolver (WebAppContext context)
80 {
81 _context = context;
82 }
83
84 public boolean isExcluded (String name)
85 {
86 if (_context.isSystemClass(name)) return true;
87 if (_context.isServerClass(name)) return false;
88 return false;
89 }
90
91 public boolean shouldOverride (String name)
92 {
93
94
95 if (_context.isParentLoaderPriority())
96 return false;
97 return true;
98 }
99 }
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 public class ContainerClassNameResolver implements ClassNameResolver
115 {
116 private WebAppContext _context;
117
118 public ContainerClassNameResolver (WebAppContext context)
119 {
120 _context = context;
121 }
122 public boolean isExcluded (String name)
123 {
124 if (_context.isSystemClass(name)) return false;
125 if (_context.isServerClass(name)) return true;
126 return false;
127 }
128
129 public boolean shouldOverride (String name)
130 {
131
132 if (_context.isParentLoaderPriority())
133 return true;
134 return false;
135 }
136 }
137
138 @Override
139 public void preConfigure(final WebAppContext context) throws Exception
140 {
141 }
142
143
144 @Override
145 public void deconfigure(WebAppContext context) throws Exception
146 {
147 context.removeAttribute(CLASS_INHERITANCE_MAP);
148 context.removeAttribute(CONTAINER_INITIALIZERS);
149 ServletContainerInitializerListener listener = (ServletContainerInitializerListener)context.getAttribute(CONTAINER_INITIALIZER_LISTENER);
150 if (listener != null)
151 {
152 context.removeBean(listener);
153 context.removeAttribute(CONTAINER_INITIALIZER_LISTENER);
154 }
155 }
156
157
158
159
160 @Override
161 public void configure(WebAppContext context) throws Exception
162 {
163 boolean metadataComplete = context.getMetaData().isMetaDataComplete();
164 context.addDecorator(new AnnotationDecorator(context));
165
166
167
168 AnnotationParser parser = null;
169 if (!metadataComplete)
170 {
171
172 if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered())
173 {
174 _discoverableAnnotationHandlers.add(new WebServletAnnotationHandler(context));
175 _discoverableAnnotationHandlers.add(new WebFilterAnnotationHandler(context));
176 _discoverableAnnotationHandlers.add(new WebListenerAnnotationHandler(context));
177 }
178 }
179 else
180 if (LOG.isDebugEnabled()) LOG.debug("Metadata-complete==true, not processing discoverable servlet annotations for context "+context);
181
182
183
184
185
186 createServletContainerInitializerAnnotationHandlers(context, getNonExcludedInitializers(context));
187
188 if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
189 {
190 parser = createAnnotationParser();
191 if (LOG.isDebugEnabled()) LOG.debug("Scanning all classses for annotations: webxmlVersion="+context.getServletContext().getEffectiveMajorVersion()+" configurationDiscovered="+context.isConfigurationDiscovered());
192 parseContainerPath(context, parser);
193
194
195
196
197
198 parseWebInfClasses(context, parser);
199 parseWebInfLib (context, parser);
200
201 for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
202 context.getMetaData().addDiscoveredAnnotations(((AbstractDiscoverableAnnotationHandler)h).getAnnotationList());
203 }
204 }
205
206
207
208
209
210
211 @Override
212 public void postConfigure(WebAppContext context) throws Exception
213 {
214 MultiMap map = (MultiMap)context.getAttribute(CLASS_INHERITANCE_MAP);
215 if (map != null)
216 map.clear();
217
218 context.removeAttribute(CLASS_INHERITANCE_MAP);
219
220 List<ContainerInitializer> initializers = (List<ContainerInitializer>)context.getAttribute(CONTAINER_INITIALIZERS);
221 if (initializers != null)
222 initializers.clear();
223 if (_discoverableAnnotationHandlers != null)
224 _discoverableAnnotationHandlers.clear();
225
226 _classInheritanceHandler = null;
227 if (_containerInitializerAnnotationHandlers != null)
228 _containerInitializerAnnotationHandlers.clear();
229
230 super.postConfigure(context);
231 }
232
233
234
235
236
237 protected AnnotationParser createAnnotationParser()
238 {
239 return new AnnotationParser();
240 }
241
242
243
244
245 @Override
246 public void cloneConfigure(WebAppContext template, WebAppContext context) throws Exception
247 {
248 context.addDecorator(new AnnotationDecorator(context));
249 }
250
251
252
253
254
255
256
257
258 public void createServletContainerInitializerAnnotationHandlers (WebAppContext context, List<ServletContainerInitializer> scis)
259 throws Exception
260 {
261
262
263 if (scis == null || scis.isEmpty())
264 return;
265
266
267
268 List<ContainerInitializer> initializers = new ArrayList<ContainerInitializer>();
269 context.setAttribute(CONTAINER_INITIALIZERS, initializers);
270
271 for (ServletContainerInitializer service : scis)
272 {
273 HandlesTypes annotation = service.getClass().getAnnotation(HandlesTypes.class);
274 ContainerInitializer initializer = new ContainerInitializer();
275 initializer.setTarget(service);
276 initializers.add(initializer);
277 if (annotation != null)
278 {
279
280 Class[] classes = annotation.value();
281 if (classes != null)
282 {
283 initializer.setInterestedTypes(classes);
284
285
286
287
288 if (context.getAttribute(CLASS_INHERITANCE_MAP) == null)
289 {
290 MultiMap map = new MultiMap();
291 context.setAttribute(CLASS_INHERITANCE_MAP, map);
292 _classInheritanceHandler = new ClassInheritanceHandler(map);
293 }
294
295 for (Class c: classes)
296 {
297
298
299 if (c.isAnnotation())
300 {
301 if (LOG.isDebugEnabled()) LOG.debug("Registering annotation handler for "+c.getName());
302
303 _containerInitializerAnnotationHandlers.add(new ContainerInitializerAnnotationHandler(initializer, c));
304 }
305 }
306 }
307 else
308 if (LOG.isDebugEnabled()) LOG.debug("No classes in HandlesTypes on initializer "+service.getClass());
309 }
310 else
311 if (LOG.isDebugEnabled()) LOG.debug("No annotation on initializer "+service.getClass());
312 }
313
314
315
316
317 ServletContainerInitializerListener listener = (ServletContainerInitializerListener)context.getAttribute(CONTAINER_INITIALIZER_LISTENER);
318 if (listener != null)
319 throw new IllegalStateException("ServletContainerInitializerListener already exists");
320 listener = new ServletContainerInitializerListener();
321 listener.setWebAppContext(context);
322 context.setAttribute(CONTAINER_INITIALIZER_LISTENER, listener);
323 context.addBean(listener, true);
324 }
325
326
327
328
329
330
331
332
333
334
335 public boolean isFromExcludedJar (WebAppContext context, ServletContainerInitializer service)
336 throws Exception
337 {
338 List<Resource> orderedJars = context.getMetaData().getOrderedWebInfJars();
339
340
341 if (context.getMetaData().getOrdering() == null)
342 return false;
343
344
345 if (orderedJars.isEmpty())
346 return true;
347
348 String loadingJarName = Thread.currentThread().getContextClassLoader().getResource(service.getClass().getName().replace('.','/')+".class").toString();
349
350 int i = loadingJarName.indexOf(".jar");
351 if (i < 0)
352 return false;
353
354 loadingJarName = loadingJarName.substring(0,i+4);
355 loadingJarName = (loadingJarName.startsWith("jar:")?loadingJarName.substring(4):loadingJarName);
356 URI loadingJarURI = Resource.newResource(loadingJarName).getURI();
357 boolean found = false;
358 Iterator<Resource> itor = orderedJars.iterator();
359 while (!found && itor.hasNext())
360 {
361 Resource r = itor.next();
362 found = r.getURI().equals(loadingJarURI);
363 }
364
365 return !found;
366 }
367
368
369
370
371
372
373
374
375 public List<ServletContainerInitializer> getNonExcludedInitializers (WebAppContext context)
376 throws Exception
377 {
378 List<ServletContainerInitializer> nonExcludedInitializers = new ArrayList<ServletContainerInitializer>();
379
380
381 ServiceLoader<ServletContainerInitializer> loadedInitializers = ServiceLoader.load(ServletContainerInitializer.class, context.getClassLoader());
382
383 if (loadedInitializers != null)
384 {
385 for (ServletContainerInitializer service : loadedInitializers)
386 {
387 if (!isFromExcludedJar(context, service))
388 nonExcludedInitializers.add(service);
389 }
390 }
391 return nonExcludedInitializers;
392 }
393
394
395
396
397
398
399
400
401
402
403
404 public void parseContainerPath (final WebAppContext context, final AnnotationParser parser)
405 throws Exception
406 {
407
408 LOG.debug("Scanning container jars");
409
410
411 parser.clearHandlers();
412 for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
413 {
414 if (h instanceof AbstractDiscoverableAnnotationHandler)
415 ((AbstractDiscoverableAnnotationHandler)h).setResource(null);
416 }
417 parser.registerHandlers(_discoverableAnnotationHandlers);
418 parser.registerHandler(_classInheritanceHandler);
419 parser.registerHandlers(_containerInitializerAnnotationHandlers);
420
421
422 ArrayList<URI> containerUris = new ArrayList<URI>();
423 for (Resource r : context.getMetaData().getContainerResources())
424 {
425 URI uri = r.getURI();
426 containerUris.add(uri);
427 }
428
429 parser.parse (containerUris.toArray(new URI[containerUris.size()]),
430 new ContainerClassNameResolver (context));
431 }
432
433
434
435
436
437
438
439
440
441 public void parseWebInfLib (final WebAppContext context, final AnnotationParser parser)
442 throws Exception
443 {
444 List<FragmentDescriptor> frags = context.getMetaData().getFragments();
445
446
447
448
449 ArrayList<URI> webInfUris = new ArrayList<URI>();
450
451 List<Resource> jars = context.getMetaData().getOrderedWebInfJars();
452
453
454 if (jars == null || jars.isEmpty())
455 jars = context.getMetaData().getWebInfJars();
456
457 for (Resource r : jars)
458 {
459
460 parser.clearHandlers();
461
462 URI uri = r.getURI();
463 FragmentDescriptor f = getFragmentFromJar(r, frags);
464
465
466
467
468
469 if (f == null || !isMetaDataComplete(f) || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
470 {
471
472 parser.registerHandler(_classInheritanceHandler);
473
474
475 parser.registerHandlers(_containerInitializerAnnotationHandlers);
476
477
478 if (f == null || !isMetaDataComplete(f))
479 {
480 for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
481 {
482 if (h instanceof AbstractDiscoverableAnnotationHandler)
483 ((AbstractDiscoverableAnnotationHandler)h).setResource(r);
484 }
485 parser.registerHandlers(_discoverableAnnotationHandlers);
486 }
487
488 parser.parse(uri, new WebAppClassNameResolver(context));
489 }
490 }
491 }
492
493
494
495
496
497
498
499
500 public void parseWebInfClasses (final WebAppContext context, final AnnotationParser parser)
501 throws Exception
502 {
503 LOG.debug("Scanning classes in WEB-INF/classes");
504
505 parser.clearHandlers();
506 for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
507 {
508 if (h instanceof AbstractDiscoverableAnnotationHandler)
509 ((AbstractDiscoverableAnnotationHandler)h).setResource(null);
510 }
511 parser.registerHandlers(_discoverableAnnotationHandlers);
512 parser.registerHandler(_classInheritanceHandler);
513 parser.registerHandlers(_containerInitializerAnnotationHandlers);
514
515 for (Resource dir : context.getMetaData().getWebInfClassesDirs())
516 {
517 parser.parseDir(dir, new WebAppClassNameResolver(context));
518 }
519 }
520
521
522
523
524
525
526
527
528
529
530
531 public FragmentDescriptor getFragmentFromJar (Resource jar, List<FragmentDescriptor> frags)
532 throws Exception
533 {
534
535 FragmentDescriptor d = null;
536 for (FragmentDescriptor frag: frags)
537 {
538 Resource fragResource = frag.getResource();
539 if (Resource.isContainedIn(fragResource,jar))
540 {
541 d = frag;
542 break;
543 }
544 }
545 return d;
546 }
547
548 public boolean isMetaDataComplete (WebDescriptor d)
549 {
550 return (d!=null && d.getMetaDataComplete() == MetaDataComplete.True);
551 }
552
553
554 }