1
2
3
4
5
6
7
8
9
10
11
12
13 package org.eclipse.jetty.annotations;
14
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.net.URI;
18 import java.net.URL;
19 import java.net.URLClassLoader;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.jar.JarEntry;
28
29 import org.eclipse.jetty.util.Loader;
30 import org.eclipse.jetty.util.log.Log;
31 import org.eclipse.jetty.util.log.Logger;
32 import org.eclipse.jetty.util.resource.Resource;
33 import org.eclipse.jetty.webapp.JarScanner;
34 import org.objectweb.asm.AnnotationVisitor;
35 import org.objectweb.asm.ClassReader;
36 import org.objectweb.asm.FieldVisitor;
37 import org.objectweb.asm.MethodVisitor;
38 import org.objectweb.asm.commons.EmptyVisitor;
39
40
41
42
43
44
45
46 public class AnnotationParser
47 {
48 private static final Logger LOG = Log.getLogger(AnnotationParser.class);
49
50 protected List<String> _parsedClassNames = new ArrayList<String>();
51 protected Map<String, List<DiscoverableAnnotationHandler>> _annotationHandlers = new HashMap<String, List<DiscoverableAnnotationHandler>>();
52 protected List<ClassHandler> _classHandlers = new ArrayList<ClassHandler>();
53 protected List<MethodHandler> _methodHandlers = new ArrayList<MethodHandler>();
54 protected List<FieldHandler> _fieldHandlers = new ArrayList<FieldHandler>();
55
56 public static String normalize (String name)
57 {
58 if (name==null)
59 return null;
60
61 if (name.startsWith("L") && name.endsWith(";"))
62 name = name.substring(1, name.length()-1);
63
64 if (name.endsWith(".class"))
65 name = name.substring(0, name.length()-".class".length());
66
67 return name.replace('/', '.');
68 }
69
70
71
72 public abstract class Value
73 {
74 String _name;
75
76 public Value (String name)
77 {
78 _name = name;
79 }
80
81 public String getName()
82 {
83 return _name;
84 }
85
86 public abstract Object getValue();
87
88 }
89
90
91
92
93 public class SimpleValue extends Value
94 {
95 Object _val;
96
97 public SimpleValue(String name)
98 {
99 super(name);
100 }
101
102 public void setValue(Object val)
103 {
104 _val=val;
105 }
106 public Object getValue()
107 {
108 return _val;
109 }
110
111 public String toString()
112 {
113 return "("+getName()+":"+_val+")";
114 }
115 }
116
117 public class ListValue extends Value
118 {
119 List<Value> _val;
120
121 public ListValue (String name)
122 {
123 super(name);
124 _val = new ArrayList<Value>();
125 }
126
127 public Object getValue()
128 {
129 return _val;
130 }
131
132 public List<Value> getList()
133 {
134 return _val;
135 }
136
137 public void addValue (Value v)
138 {
139 _val.add(v);
140 }
141
142 public int size ()
143 {
144 return _val.size();
145 }
146
147 public String toString()
148 {
149 StringBuffer buff = new StringBuffer();
150 buff.append("(");
151 buff.append(getName());
152 buff.append(":");
153 for (Value n: _val)
154 {
155 buff.append(" "+n.toString());
156 }
157 buff.append(")");
158
159 return buff.toString();
160 }
161 }
162
163
164
165 public interface DiscoverableAnnotationHandler
166 {
167 public void handleClass (String className, int version, int access,
168 String signature, String superName, String[] interfaces,
169 String annotation, List<Value>values);
170
171 public void handleMethod (String className, String methodName, int access,
172 String desc, String signature,String[] exceptions,
173 String annotation, List<Value>values);
174
175 public void handleField (String className, String fieldName, int access,
176 String fieldType, String signature, Object value,
177 String annotation, List<Value>values);
178 }
179
180
181 public interface ClassHandler
182 {
183 public void handle (String className, int version, int access, String signature, String superName, String[] interfaces);
184 }
185
186 public interface MethodHandler
187 {
188 public void handle (String className, String methodName, int access, String desc, String signature,String[] exceptions);
189 }
190
191 public interface FieldHandler
192 {
193 public void handle (String className, String fieldName, int access, String fieldType, String signature, Object value);
194 }
195
196 public class MyAnnotationVisitor implements AnnotationVisitor
197 {
198 List<Value> _annotationValues;
199 String _annotationName;
200
201 public MyAnnotationVisitor (String annotationName, List<Value> values)
202 {
203 _annotationValues = values;
204 _annotationName = annotationName;
205 }
206
207 public List<Value> getAnnotationValues()
208 {
209 return _annotationValues;
210 }
211
212
213
214
215
216 public void visit(String aname, Object avalue)
217 {
218 SimpleValue v = new SimpleValue(aname);
219 v.setValue(avalue);
220 _annotationValues.add(v);
221 }
222
223
224
225
226
227 public AnnotationVisitor visitAnnotation(String name, String desc)
228 {
229 String s = normalize(desc);
230 ListValue v = new ListValue(s);
231 _annotationValues.add(v);
232 MyAnnotationVisitor visitor = new MyAnnotationVisitor(s, v.getList());
233 return visitor;
234 }
235
236
237
238
239
240 public AnnotationVisitor visitArray(String name)
241 {
242 ListValue v = new ListValue(name);
243 _annotationValues.add(v);
244 MyAnnotationVisitor visitor = new MyAnnotationVisitor(null, v.getList());
245 return visitor;
246 }
247
248
249
250
251
252 public void visitEnum(String name, String desc, String value)
253 {
254
255 }
256
257 public void visitEnd()
258 {
259 }
260 }
261
262
263
264
265
266
267
268
269
270 public class MyClassVisitor extends EmptyVisitor
271 {
272 String _className;
273 int _access;
274 String _signature;
275 String _superName;
276 String[] _interfaces;
277 int _version;
278
279
280 public void visit (int version,
281 final int access,
282 final String name,
283 final String signature,
284 final String superName,
285 final String[] interfaces)
286 {
287 _className = normalize(name);
288 _access = access;
289 _signature = signature;
290 _superName = superName;
291 _interfaces = interfaces;
292 _version = version;
293
294 _parsedClassNames.add(_className);
295
296 String[] normalizedInterfaces = null;
297 if (interfaces!= null)
298 {
299 normalizedInterfaces = new String[interfaces.length];
300 int i=0;
301 for (String s : interfaces)
302 normalizedInterfaces[i++] = normalize(s);
303 }
304
305 for (ClassHandler h : AnnotationParser.this._classHandlers)
306 {
307 h.handle(_className, _version, _access, _signature, normalize(_superName), normalizedInterfaces);
308 }
309 }
310
311 public AnnotationVisitor visitAnnotation (String desc, boolean visible)
312 {
313 MyAnnotationVisitor visitor = new MyAnnotationVisitor(normalize(desc), new ArrayList<Value>())
314 {
315 public void visitEnd()
316 {
317 super.visitEnd();
318
319
320 List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
321 if (handlers != null)
322 {
323 for (DiscoverableAnnotationHandler h:handlers)
324 {
325 h.handleClass(_className, _version, _access, _signature, _superName, _interfaces, _annotationName, _annotationValues);
326 }
327 }
328 }
329 };
330
331 return visitor;
332 }
333
334 public MethodVisitor visitMethod (final int access,
335 final String name,
336 final String methodDesc,
337 final String signature,
338 final String[] exceptions)
339 {
340
341 return new EmptyVisitor ()
342 {
343 public AnnotationVisitor visitAnnotation(String desc, boolean visible)
344 {
345 MyAnnotationVisitor visitor = new MyAnnotationVisitor (normalize(desc), new ArrayList<Value>())
346 {
347 public void visitEnd()
348 {
349 super.visitEnd();
350
351 List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
352 if (handlers != null)
353 {
354 for (DiscoverableAnnotationHandler h:handlers)
355 {
356 h.handleMethod(_className, name, access, methodDesc, signature, exceptions, _annotationName, _annotationValues);
357 }
358 }
359 }
360 };
361
362 return visitor;
363 }
364 };
365 }
366
367 public FieldVisitor visitField (final int access,
368 final String fieldName,
369 final String fieldType,
370 final String signature,
371 final Object value)
372 {
373
374 return new EmptyVisitor ()
375 {
376 public AnnotationVisitor visitAnnotation(String desc, boolean visible)
377 {
378 MyAnnotationVisitor visitor = new MyAnnotationVisitor(normalize(desc), new ArrayList<Value>())
379 {
380 public void visitEnd()
381 {
382 super.visitEnd();
383 List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
384 if (handlers != null)
385 {
386 for (DiscoverableAnnotationHandler h:handlers)
387 {
388 h.handleField(_className, fieldName, access, fieldType, signature, value, _annotationName, _annotationValues);
389 }
390 }
391 }
392 };
393 return visitor;
394 }
395 };
396 }
397 }
398
399
400
401
402
403
404
405
406
407 public void registerAnnotationHandler (String annotationName, DiscoverableAnnotationHandler handler)
408 {
409 List<DiscoverableAnnotationHandler> handlers = _annotationHandlers.get(annotationName);
410 if (handlers == null)
411 {
412 handlers = new ArrayList<DiscoverableAnnotationHandler>();
413 _annotationHandlers.put(annotationName, handlers);
414 }
415 handlers.add(handler);
416 }
417
418 public List<DiscoverableAnnotationHandler> getAnnotationHandlers(String annotationName)
419 {
420 List<DiscoverableAnnotationHandler> handlers = _annotationHandlers.get(annotationName);
421 if (handlers == null)
422 return Collections.emptyList();
423 return new ArrayList<DiscoverableAnnotationHandler>();
424 }
425
426 public List<DiscoverableAnnotationHandler> getAnnotationHandlers()
427 {
428 List<DiscoverableAnnotationHandler> allHandlers = new ArrayList<DiscoverableAnnotationHandler>();
429 for (List<DiscoverableAnnotationHandler> list:_annotationHandlers.values())
430 allHandlers.addAll(list);
431 return allHandlers;
432 }
433
434 public void registerClassHandler (ClassHandler handler)
435 {
436 _classHandlers.add(handler);
437 }
438
439 public boolean isParsed (String className)
440 {
441 return _parsedClassNames.contains(className);
442 }
443
444 public void parse (String className, ClassNameResolver resolver)
445 throws Exception
446 {
447 if (className == null)
448 return;
449
450 if (!resolver.isExcluded(className))
451 {
452 if (!isParsed(className) || resolver.shouldOverride(className))
453 {
454 className = className.replace('.', '/')+".class";
455 URL resource = Loader.getResource(this.getClass(), className, false);
456 if (resource!= null)
457 scanClass(resource.openStream());
458 }
459 }
460 }
461
462 public void parse (Class clazz, ClassNameResolver resolver, boolean visitSuperClasses)
463 throws Exception
464 {
465 Class cz = clazz;
466 while (cz != null)
467 {
468 if (!resolver.isExcluded(cz.getName()))
469 {
470 if (!isParsed(cz.getName()) || resolver.shouldOverride(cz.getName()))
471 {
472 String nameAsResource = cz.getName().replace('.', '/')+".class";
473 URL resource = Loader.getResource(this.getClass(), nameAsResource, false);
474 if (resource!= null)
475 scanClass(resource.openStream());
476 }
477 }
478 if (visitSuperClasses)
479 cz = cz.getSuperclass();
480 else
481 cz = null;
482 }
483 }
484
485 public void parse (String[] classNames, ClassNameResolver resolver)
486 throws Exception
487 {
488 if (classNames == null)
489 return;
490
491 parse(Arrays.asList(classNames), resolver);
492 }
493
494 public void parse (List<String> classNames, ClassNameResolver resolver)
495 throws Exception
496 {
497 for (String s:classNames)
498 {
499 if ((resolver == null) || (!resolver.isExcluded(s) && (!isParsed(s) || resolver.shouldOverride(s))))
500 {
501 s = s.replace('.', '/')+".class";
502 URL resource = Loader.getResource(this.getClass(), s, false);
503 if (resource!= null)
504 scanClass(resource.openStream());
505 }
506 }
507 }
508
509 public void parse (Resource dir, ClassNameResolver resolver)
510 throws Exception
511 {
512 if (!dir.isDirectory() || !dir.exists())
513 return;
514
515
516 String[] files=dir.list();
517 for (int f=0;files!=null && f<files.length;f++)
518 {
519 try
520 {
521 Resource res = dir.addPath(files[f]);
522 if (res.isDirectory())
523 parse(res, resolver);
524 String name = res.getName();
525 if (name.endsWith(".class"))
526 {
527 if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name))))
528 scanClass(res.getURL().openStream());
529
530 }
531 }
532 catch (Exception ex)
533 {
534 LOG.warn(Log.EXCEPTION,ex);
535 }
536 }
537 }
538
539
540
541
542
543
544
545
546
547
548
549 public void parse (ClassLoader loader, boolean visitParents, boolean nullInclusive, final ClassNameResolver resolver)
550 throws Exception
551 {
552 if (loader==null)
553 return;
554
555 if (!(loader instanceof URLClassLoader))
556 return;
557
558 JarScanner scanner = new JarScanner()
559 {
560 public void processEntry(URI jarUri, JarEntry entry)
561 {
562 try
563 {
564 String name = entry.getName();
565 if (name.toLowerCase().endsWith(".class"))
566 {
567 String shortName = name.replace('/', '.').substring(0,name.length()-6);
568 if ((resolver == null)
569 ||
570 (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
571 {
572
573 Resource clazz = Resource.newResource("jar:"+jarUri+"!/"+name);
574 scanClass(clazz.getInputStream());
575 }
576 }
577 }
578 catch (Exception e)
579 {
580 LOG.warn("Problem processing jar entry "+entry, e);
581 }
582 }
583
584 };
585
586 scanner.scan(null, loader, nullInclusive, visitParents);
587 }
588
589
590
591
592
593
594
595
596 public void parse (URI[] uris, final ClassNameResolver resolver)
597 throws Exception
598 {
599 if (uris==null)
600 return;
601
602 JarScanner scanner = new JarScanner()
603 {
604 public void processEntry(URI jarUri, JarEntry entry)
605 {
606 try
607 {
608 String name = entry.getName();
609 if (name.toLowerCase().endsWith(".class"))
610 {
611 String shortName = name.replace('/', '.').substring(0,name.length()-6);
612
613 if ((resolver == null)
614 ||
615 (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
616 {
617 Resource clazz = Resource.newResource("jar:"+jarUri+"!/"+name);
618 scanClass(clazz.getInputStream());
619
620 }
621 }
622 }
623 catch (Exception e)
624 {
625 LOG.warn("Problem processing jar entry "+entry, e);
626 }
627 }
628
629 };
630 scanner.scan(null, uris, true);
631 }
632
633 public void parse (URI uri, final ClassNameResolver resolver)
634 throws Exception
635 {
636 if (uri == null)
637 return;
638 URI[] uris = {uri};
639 parse(uris, resolver);
640 }
641
642 protected void scanClass (InputStream is)
643 throws IOException
644 {
645 ClassReader reader = new ClassReader(is);
646 reader.accept(new MyClassVisitor(), ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
647 }
648 }
649