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