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