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 {
458 Resource r = Resource.newResource(resource);
459 scanClass(r.getInputStream());
460 }
461 }
462 }
463 }
464
465 public void parse (Class clazz, ClassNameResolver resolver, boolean visitSuperClasses)
466 throws Exception
467 {
468 Class cz = clazz;
469 while (cz != null)
470 {
471 if (!resolver.isExcluded(cz.getName()))
472 {
473 if (!isParsed(cz.getName()) || resolver.shouldOverride(cz.getName()))
474 {
475 String nameAsResource = cz.getName().replace('.', '/')+".class";
476 URL resource = Loader.getResource(this.getClass(), nameAsResource, false);
477 if (resource!= null)
478 {
479 Resource r = Resource.newResource(resource);
480 scanClass(r.getInputStream());
481 }
482 }
483 }
484 if (visitSuperClasses)
485 cz = cz.getSuperclass();
486 else
487 cz = null;
488 }
489 }
490
491 public void parse (String[] classNames, ClassNameResolver resolver)
492 throws Exception
493 {
494 if (classNames == null)
495 return;
496
497 parse(Arrays.asList(classNames), resolver);
498 }
499
500 public void parse (List<String> classNames, ClassNameResolver resolver)
501 throws Exception
502 {
503 for (String s:classNames)
504 {
505 if ((resolver == null) || (!resolver.isExcluded(s) && (!isParsed(s) || resolver.shouldOverride(s))))
506 {
507 s = s.replace('.', '/')+".class";
508 URL resource = Loader.getResource(this.getClass(), s, false);
509 if (resource!= null)
510 {
511 Resource r = Resource.newResource(resource);
512 scanClass(r.getInputStream());
513 }
514 }
515 }
516 }
517
518 public void parse (Resource dir, ClassNameResolver resolver)
519 throws Exception
520 {
521 if (!dir.isDirectory() || !dir.exists())
522 return;
523
524
525 String[] files=dir.list();
526 for (int f=0;files!=null && f<files.length;f++)
527 {
528 try
529 {
530 Resource res = dir.addPath(files[f]);
531 if (res.isDirectory())
532 parse(res, resolver);
533 String name = res.getName();
534 if (name.endsWith(".class"))
535 {
536 if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name))))
537 {
538 Resource r = Resource.newResource(res.getURL());
539 scanClass(r.getInputStream());
540 }
541
542 }
543 }
544 catch (Exception ex)
545 {
546 LOG.warn(Log.EXCEPTION,ex);
547 }
548 }
549 }
550
551
552
553
554
555
556
557
558
559
560
561 public void parse (ClassLoader loader, boolean visitParents, boolean nullInclusive, final ClassNameResolver resolver)
562 throws Exception
563 {
564 if (loader==null)
565 return;
566
567 if (!(loader instanceof URLClassLoader))
568 return;
569
570 JarScanner scanner = new JarScanner()
571 {
572 public void processEntry(URI jarUri, JarEntry entry)
573 {
574 try
575 {
576 String name = entry.getName();
577 if (name.toLowerCase().endsWith(".class"))
578 {
579 String shortName = name.replace('/', '.').substring(0,name.length()-6);
580 if ((resolver == null)
581 ||
582 (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
583 {
584
585 Resource clazz = Resource.newResource("jar:"+jarUri+"!/"+name);
586 scanClass(clazz.getInputStream());
587 }
588 }
589 }
590 catch (Exception e)
591 {
592 LOG.warn("Problem processing jar entry "+entry, e);
593 }
594 }
595
596 };
597
598 scanner.scan(null, loader, nullInclusive, visitParents);
599 }
600
601
602
603
604
605
606
607
608 public void parse (URI[] uris, final ClassNameResolver resolver)
609 throws Exception
610 {
611 if (uris==null)
612 return;
613
614 JarScanner scanner = new JarScanner()
615 {
616 public void processEntry(URI jarUri, JarEntry entry)
617 {
618 try
619 {
620 String name = entry.getName();
621 if (name.toLowerCase().endsWith(".class"))
622 {
623 String shortName = name.replace('/', '.').substring(0,name.length()-6);
624
625 if ((resolver == null)
626 ||
627 (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
628 {
629 Resource clazz = Resource.newResource("jar:"+jarUri+"!/"+name);
630 scanClass(clazz.getInputStream());
631
632 }
633 }
634 }
635 catch (Exception e)
636 {
637 LOG.warn("Problem processing jar entry "+entry, e);
638 }
639 }
640
641 };
642 scanner.scan(null, uris, true);
643 }
644
645 public void parse (URI uri, final ClassNameResolver resolver)
646 throws Exception
647 {
648 if (uri == null)
649 return;
650 URI[] uris = {uri};
651 parse(uris, resolver);
652 }
653
654 private void scanClass (InputStream is)
655 throws IOException
656 {
657 ClassReader reader = new ClassReader(is);
658 reader.accept(new MyClassVisitor(), ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
659 }
660 }