DispatchingVisitor.java
biz/hammurapi/util/DispatchingVisitor.java
Violations
Inspector |
Message |
Severity |
Location |
Java Inspector 048 |
Copyrights information should be present in each file. |
1 |
|
Java Inspector 086 |
Use equals() instead of == or != to compare objects. |
1 |
657:37
|
Java Inspector 086 |
Use equals() instead of == or != to compare objects. |
1 |
665:37
|
Java Inspector 086 |
Use equals() instead of == or != to compare objects. |
1 |
673:37
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
245:41
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
540:31
|
Java Inspector 068 |
Do not use System.out and System.err to output logging messages. Use loggers instead. |
2 |
307:67
|
Java Inspector 070-A |
Cyclomatic complexity is too high: 16, maximum allowed is 12 |
2 |
288:17
|
Java Inspector 070-A |
Cyclomatic complexity is too high: 17, maximum allowed is 12 |
2 |
521:9
|
Java Inspector 083 |
Do not use printStackTrace() for exception logging. |
2 |
313:66
|
Java Inspector 083 |
Do not use printStackTrace() for exception logging. |
2 |
319:66
|
Java Inspector 089 |
Non-private, non-local types shall be documented |
2 |
170:9
|
Java Inspector 089 |
Non-private, non-local types shall be documented |
2 |
193:9
|
Java Inspector 089 |
Undocumented method |
2 |
203:17
|
Java Inspector 089 |
Undocumented method |
2 |
207:17
|
Java Inspector 089 |
Undocumented method |
2 |
211:17
|
Java Inspector 089 |
Undocumented method |
2 |
216:17
|
Java Inspector 089 |
Undocumented method |
2 |
233:17
|
Java Inspector 089 |
Undocumented method |
2 |
248:17
|
Java Inspector 089 |
Undocumented method |
2 |
337:17
|
Java Inspector 089 |
Undocumented method |
2 |
410:17
|
Java Inspector 089 |
Undocumented method |
2 |
417:9
|
Java Inspector 089 |
Undocumented method |
2 |
421:9
|
Java Inspector 089 |
Undocumented method |
2 |
462:9
|
Java Inspector 089 |
Method is not properly documented |
2 |
494:9
|
Java Inspector 089 |
Undocumented method |
2 |
498:9
|
Java Inspector 089 |
Constructor is not properly documented |
2 |
521:9
|
Java Inspector 089 |
Parameter targets is not documented |
2 |
521:9
|
Java Inspector 089 |
Parameter exceptionSink is not documented |
2 |
521:9
|
Java Inspector 089 |
Undocumented parameter listener |
2 |
521:9
|
Java Inspector 089 |
Undocumented constructor |
2 |
596:9
|
Java Inspector 089 |
Constructor is not properly documented |
2 |
604:9
|
Java Inspector 089 |
Parameter target is not documented |
2 |
604:9
|
Java Inspector 089 |
Parameter exceptionSink is not documented |
2 |
604:9
|
Java Inspector 089 |
Undocumented constructor |
2 |
608:9
|
Java Inspector 089 |
Method is not properly documented |
2 |
615:9
|
Java Inspector 089 |
Undocumented method |
2 |
619:9
|
Java Inspector 089 |
Undocumented method |
2 |
624:9
|
Java Inspector 089 |
Parameter target is not documented |
2 |
653:9
|
Java Inspector 089 |
Undocumented parameter executionContext |
2 |
685:9
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
217:32
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
217:59
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
217:71
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
217:95
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
249:53
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
249:63
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
249:74
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
307:75
|
Java Inspector 040 |
Parameter name handlers clashes with field name in DispatchingVisitor |
3 |
581:36
|
Java Inspector 051 |
It is good practice to call in any case super() in a constructor. |
3 |
267:17
|
Java Inspector 051 |
It is good practice to call in any case super() in a constructor. |
3 |
521:9
|
Java Inspector 051 |
It is good practice to call in any case super() in a constructor. |
3 |
596:9
|
Java Inspector 051 |
It is good practice to call in any case super() in a constructor. |
3 |
604:9
|
Java Inspector 051 |
It is good practice to call in any case super() in a constructor. |
3 |
608:9
|
Java Inspector 090 |
Unnecessary else part in if. The main part terminates control flow (return, break, throw, or continue). |
3 |
325:41
|
Java Inspector 090 |
Unnecessary else part in if. The main part terminates control flow (return, break, throw, or continue). |
3 |
349:41
|
Java Inspector 090 |
Unnecessary else part in if. The main part terminates control flow (return, break, throw, or continue). |
3 |
351:48
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package biz.hammurapi.util;
24
25import java.lang.reflect.Array;
26import java.lang.reflect.InvocationTargetException;
27import java.lang.reflect.Method;
28import java.util.ArrayList;
29import java.util.Arrays;
30import java.util.Collection;
31import java.util.Collections;
32import java.util.HashMap;
33import java.util.IdentityHashMap;
34import java.util.Iterator;
35import java.util.LinkedList;
36import java.util.List;
37import java.util.Map;
38
39import biz.hammurapi.config.Command;
40
41
42
43
44
45
46
47public class DispatchingVisitor implements PoliteVisitor, VisitorStackSource, Command {
48 private static final String APPROVE = "approve";
49 private static final String VERIFY = "verify";
50 private static final String LEAVE = "leave";
51 private static final String VISIT = "visit";
52 private Collection targets;
53 private VisitorExceptionSink exceptionSink;
54 private Map handlers=new HashMap();
55 private Map leaveHandlers=new HashMap();
56 private Map verifyHandlers=new HashMap();
57 private Map filterHandlers=new HashMap();
58 private Collection listeners=new ArrayList();
59 private Collection classesOfInterest=new ArrayList();
60 private Collection unmodifiableClassesOfInterest=Collections.unmodifiableCollection(classesOfInterest);
61
62 private Collection handlerList=new ArrayList();
63 private Collection leaveHandlerList=new ArrayList();
64 private Collection verifyHandlerList=new ArrayList();
65 private Collection filterHandlerList=new ArrayList();
66
67
68
69
70
71 private Collection getHandlers(Class clazz) {
72 synchronized (handlers) {
73 List ret=(List) handlers.get(clazz);
74 if (ret==null) {
75 ret=new ArrayList();
76 handlers.put(clazz, ret);
77 Iterator it=handlerList.iterator();
78 while (it.hasNext()) {
79 InvocationHandler handler=(InvocationHandler) it.next();
80 if (handler.method.getParameterTypes()[0].isAssignableFrom(clazz)) {
81 ret.add(handler);
82 }
83 }
84 Collections.sort(ret);
85 }
86 return ret;
87 }
88 }
89
90
91
92
93
94 private Collection getLeaveHandlers(Class clazz) {
95 synchronized (leaveHandlers) {
96 List ret=(List) leaveHandlers.get(clazz);
97 if (ret==null) {
98 ret=new ArrayList();
99 leaveHandlers.put(clazz, ret);
100 Iterator it=leaveHandlerList.iterator();
101 while (it.hasNext()) {
102 InvocationHandler handler=(InvocationHandler) it.next();
103 if (handler.method.getParameterTypes()[0].isAssignableFrom(clazz)) {
104 ret.add(handler);
105 }
106 }
107 Collections.sort(ret);
108 Collections.reverse(ret);
109 }
110 return ret;
111 }
112 }
113
114
115
116
117
118 private Collection getVerifyHandlers(Class clazz) {
119 synchronized (verifyHandlers) {
120 List ret=(List) verifyHandlers.get(clazz);
121 if (ret==null) {
122 ret=new ArrayList();
123 verifyHandlers.put(clazz, ret);
124 Iterator it=verifyHandlerList.iterator();
125 while (it.hasNext()) {
126 InvocationHandler handler=(InvocationHandler) it.next();
127 if (handler.method.getParameterTypes()[0].isAssignableFrom(clazz)) {
128 ret.add(handler);
129 }
130 }
131 Collections.sort(ret);
132 Collections.reverse(ret);
133 }
134 return ret;
135 }
136 }
137
138
139
140
141
142 private Collection getFilterHandlers(Class clazz) {
143 synchronized (filterHandlers) {
144 List ret=(List) filterHandlers.get(clazz);
145 if (ret==null) {
146 ret=new ArrayList();
147 filterHandlers.put(clazz, ret);
148 Iterator it=filterHandlerList.iterator();
149 while (it.hasNext()) {
150 InvocationHandler handler=(InvocationHandler) it.next();
151 if (handler.method.getParameterTypes()[0].isAssignableFrom(clazz)) {
152 ret.add(handler);
153 }
154 }
155 }
156 return ret;
157 }
158 }
159
160
161
162
163
164
165
166 public interface SelfListener {
167 void onInvocation(Method method, Object visitable);
168 }
169
170 public interface Listener {
171 void onInvocationRegistration(Object target, Method method);
172 void onTargetRegistration(Object target);
173 void onFilterRegistration(Method filter, Method target);
174 void noInvocationsWarning(Object target);
175 void onInvocation(Object target, Method method, Object visitable);
176 void onVisit(Object target);
177 void onLeave(Object target);
178 }
179
180
181
182
183
184
185
186
187
188
189 public interface Filter {
190 Collection getTargets();
191 }
192
193 public interface Stats {
194 long getVisits();
195 long getInvocations();
196 void reset();
197 }
198
199 private static class StatsImpl implements Stats {
200 private long visits;
201 private long invocations;
202
203 public long getVisits() {
204 return visits;
205 }
206
207 public long getInvocations() {
208 return invocations;
209 }
210
211 public void reset() {
212 visits=0;
213 invocations=0;
214 }
215
216 public String toString() {
217 return "["+Thread.currentThread()+"] "+visits+" visits, "+invocations+" invocations";
218 }
219
220 synchronized void addVisit() {
221 visits++;
222 }
223
224 synchronized void addInvocation() {
225 invocations++;
226 }
227
228 }
229
230 private int handlerCounter;
231 private StatsImpl stats=new StatsImpl();
232 private ThreadLocal threadStats=new ThreadLocal() {
233 protected Object initialValue() {
234 return new StatsImpl();
235 }
236 };
237
238 private class InvocationHandler implements Comparable {
239 boolean active=true;
240 Method method;
241 Object object;
242 int position=handlerCounter++;
243 int order;
244 List filtersList=new LinkedList();
245 ApproveInvocationHandler[] filters;
246 boolean returnsValue;
247
248 public String toString() {
249 return getClass().getName()+"["+order+" "+method+"]";
250 }
251
252 void addFilter(ApproveInvocationHandler filter) {
253 filtersList.add(filter);
254 Iterator it=listeners.iterator();
255 while (it.hasNext()) {
256 ((Listener) it.next()).onFilterRegistration(filter.method, method);
257 }
258 }
259
260 void commitFilters() {
261 filters=null;
262 if (!filtersList.isEmpty()) {
263 filters=(ApproveInvocationHandler[]) filtersList.toArray(new ApproveInvocationHandler[filtersList.size()]);
264 }
265 }
266
267 InvocationHandler(Method method, Object object) {
268 Iterator it=listeners.iterator();
269 while (it.hasNext()) {
270 ((Listener) it.next()).onInvocationRegistration(object, method);
271 }
272
273 this.method=method;
274 this.object=object;
275 this.returnsValue=!(void.class.equals(method.getReturnType()) || boolean.class.equals(method.getReturnType()) || Boolean.class.equals(method.getReturnType()));
276
277 addClassOfInterest(method.getParameterTypes()[0]);
278
279 if (object instanceof OrderedTarget) {
280 Integer ret=((OrderedTarget) object).getOrder();
281 if (ret!=null) {
282 order=ret.intValue();
283 }
284 }
285
286 }
287
288 Object invoke(Object arg) {
289 if (active) {
290 for (int i=0; filters!=null && i<filters.length; i++) {
291 if (Boolean.FALSE.equals(filters[i].invoke(arg))) {
292 return null;
293 }
294 }
295 try {
296 Iterator it=listeners.iterator();
297 while (it.hasNext()) {
298 ((Listener) it.next()).onInvocation(object, method, arg);
299 }
300 stats.addInvocation();
301 ((StatsImpl) threadStats.get()).addInvocation();
302 if (object instanceof SelfListener) {
303 ((SelfListener) object).onInvocation(method, arg);
304 }
305
306 if (!method.getParameterTypes()[0].isInstance(arg)) {
307 System.err.println(method+", "+arg.getClass());
308 }
309
310 return method.invoke(object, new Object[] {arg});
311 } catch (IllegalArgumentException e) {
312 if (exceptionSink==null) {
313 e.printStackTrace();
314 } else {
315 exceptionSink.consume(DispatchingVisitor.this, object, method, arg, e);
316 }
317 } catch (IllegalAccessException e) {
318 if (exceptionSink==null) {
319 e.printStackTrace();
320 } else {
321 exceptionSink.consume(DispatchingVisitor.this, object, method, arg, e);
322 }
323 } catch (InvocationTargetException e) {
324 Throwable targetException = e.getTargetException();
325 if (targetException instanceof Error) {
326 throw (Error) targetException;
327 } else if (exceptionSink==null) {
328 targetException.printStackTrace();
329 } else {
330 exceptionSink.consume(DispatchingVisitor.this, object, method, arg, targetException instanceof Exception ? (Exception) targetException : e);
331 }
332 }
333 }
334 return null;
335 }
336
337 public int compareTo(Object o) {
338 if (this==o) {
339 return 0;
340 }
341 InvocationHandler ih=(InvocationHandler) o;
342 if (order==ih.order) {
343 if (position==ih.position) {
344 Class c=method.getParameterTypes()[0];
345 Class ihc=ih.method.getParameterTypes()[0];
346 if (c.equals(ihc)) {
347 return method.getDeclaringClass().getName().compareTo(ih.method.getDeclaringClass().getName());
348 }
349 if (c.isAssignableFrom(ihc)) {
350 return -1;
351 } else if (ihc.isAssignableFrom(c)) {
352 return 1;
353 } else {
354 int idc=inheritanceDepth(c);
355 int ihidc=inheritanceDepth(ihc);
356 if (idc==ihidc) {
357 return method.getDeclaringClass().getName().compareTo(ih.method.getDeclaringClass().getName());
358 }
359 return idc-ihidc;
360 }
361 }
362 return position-ih.position;
363 }
364 return order==ih.order ? 0 : order>ih.order ? 1 : -1;
365 }
366 }
367
368 private int inheritanceDepth(Class clazz) {
369 if (clazz==null || Object.class.equals(clazz)) {
370 return 0;
371 }
372 int ret=0;
373 ret=Math.max(ret, inheritanceDepth(clazz.getSuperclass()));
374 for (int i=0, j=clazz.getInterfaces().length; i<j; i++) {
375 ret=Math.max(ret, inheritanceDepth(clazz.getInterfaces()[i]));
376 }
377 return ret+1;
378 }
379
380 private class ApproveInvocationHandler extends InvocationHandler {
381 private Class parameterType;
382
383 ApproveInvocationHandler(Method method, Object object) {
384 super(method, object);
385 parameterType=method.getParameterTypes()[0];
386 }
387
388 Map results=new IdentityHashMap();
389
390 Object invoke(Object arg) {
391 if (!parameterType.isInstance(arg)) {
392 return null;
393 }
394
395 if (results.containsKey(arg)) {
396 return results.get(arg);
397 }
398 Object ret=super.invoke(arg);
399 results.put(arg, ret);
400 return ret;
401 }
402
403 void remove(Object key) {
404 results.remove(key);
405 }
406 }
407
408 private ThreadLocal visitorStackTL=new ThreadLocal() {
409
410 protected Object initialValue() {
411 return new VisitorStack();
412 }
413 };
414
415 private int size;
416
417 public VisitorStack getVisitorStack() {
418 return (VisitorStack) visitorStackTL.get();
419 }
420
421 public boolean visit(Object target) {
422 getVisitorStack().push(target);
423 Iterator lit=listeners.iterator();
424 while (lit.hasNext()) {
425 ((Listener) lit.next()).onVisit(target);
426 }
427
428 if (handlerList.isEmpty()) {
429 return false;
430 }
431
432 stats.addVisit();
433 ((StatsImpl) threadStats.get()).addVisit();
434
435 if (target!=null) {
436
437 Iterator it=getVerifyHandlers(target.getClass()).iterator();
438 while (it.hasNext()) {
439 if (Boolean.FALSE.equals(((InvocationHandler) it.next()).invoke(target))) {
440 return false;
441 }
442 }
443
444
445 it=getHandlers(target.getClass()).iterator();
446 while (it.hasNext()) {
447 InvocationHandler ih=(InvocationHandler) it.next();
448 Object ret=ih.invoke(target);
449 if (Boolean.FALSE.equals(ret)) {
450 return false;
451 }
452
453 if (ret!=null && ih.returnsValue) {
454 processReturnValue(ih.object, ih.method, target, ret);
455 }
456 }
457 }
458
459 return true;
460 }
461
462 public Collection getTargets() {
463 return targets;
464 }
465
466
467
468
469
470
471
472
473
474
475 protected void processReturnValue(Object target, Method method, Object argument, Object returnValue) {
476 if (returnValue instanceof Collection) {
477 Iterator it=((Collection) returnValue).iterator();
478 while (it.hasNext()) {
479 VisitableBase.object2visitor(it.next(), this);
480 }
481 } else if (returnValue.getClass().isArray()) {
482 for (int i=0,l=Array.getLength(returnValue);i<l;i++) {
483 VisitableBase.object2visitor(Array.get(returnValue, i), this);
484 }
485 } else {
486 VisitableBase.object2visitor(returnValue, this);
487 }
488 }
489
490
491
492
493
494 public int size() {
495 return size;
496 }
497
498 public Collection getClassesOfInterest() {
499 return unmodifiableClassesOfInterest;
500 }
501
502 private void addClassOfInterest(Class clazz) {
503 Iterator it=classesOfInterest.iterator();
504 while (it.hasNext()) {
505 Class cls=(Class) it.next();
506 if (cls.isAssignableFrom(clazz)) {
507 return;
508 }
509
510 if (clazz.isAssignableFrom(cls)) {
511 it.remove();
512 }
513 }
514 classesOfInterest.add(clazz);
515 }
516
517
518
519
520
521 public DispatchingVisitor(Collection targets, VisitorExceptionSink exceptionSink, Listener listener) {
522 if (listener!=null) {
523 listeners.add(listener);
524 }
525 this.targets = Collections.unmodifiableList(new LinkedList(targets));
526 this.exceptionSink = exceptionSink;
527 Iterator it=targets.iterator();
528 while (it.hasNext()) {
529 Object target=it.next();
530 if (target instanceof DispatcherAware) {
531 ((DispatcherAware) target).setDispatcher(this);
532 }
533
534 Iterator lit=listeners.iterator();
535 while (lit.hasNext()) {
536 ((Listener) lit.next()).onTargetRegistration(target);
537 }
538
539 boolean hasInvocations=false;
540 Method[] methods=target.getClass().getMethods();
541 for (int i=0; i<methods.length; i++) {
542 if (methods[i].getParameterTypes().length == 1) {
543 Class returnType = methods[i].getReturnType();
544 if (VISIT.equals(methods[i].getName()) && (void.class.equals(returnType) || boolean.class.equals(returnType))) {
545 handlerList.add(new InvocationHandler(methods[i], target));
546 hasInvocations=true;
547 } else if (LEAVE.equals(methods[i].getName()) && void.class.equals(returnType)) {
548 leaveHandlerList.add(new InvocationHandler(methods[i], target));
549 hasInvocations=true;
550 } else if (boolean.class.equals(returnType) && VERIFY.equals(methods[i].getName())) {
551 verifyHandlerList.add(new InvocationHandler(methods[i], target));
552 hasInvocations=true;
553 } else if (target instanceof Filter && !((Filter) target).getTargets().isEmpty() && APPROVE.equals(methods[i].getName()) && boolean.class.equals(returnType)) {
554 filterHandlerList.add(new ApproveInvocationHandler(methods[i], target));
555 hasInvocations=true;
556 }
557 }
558 }
559
560 if (!hasInvocations) {
561 lit=listeners.iterator();
562 while (lit.hasNext()) {
563 ((Listener) lit.next()).noInvocationsWarning(target);
564 }
565 }
566
567 if (target instanceof Listener) {
568 listeners.add(target);
569 }
570 }
571
572 assignFilters(handlerList);
573 assignFilters(leaveHandlerList);
574
575 size = handlerList.size()+leaveHandlerList.size();
576 }
577
578
579
580
581 private void assignFilters(Collection handlers) {
582 Iterator it=handlers.iterator();
583 while (it.hasNext()) {
584 InvocationHandler handler=(InvocationHandler) it.next();
585 Iterator fit=filterHandlerList.iterator();
586 while (fit.hasNext()) {
587 ApproveInvocationHandler approveHandler=(ApproveInvocationHandler) fit.next();
588 if (((Filter) approveHandler.object).getTargets().contains(handler.object)) {
589 handler.addFilter(approveHandler);
590 }
591 }
592 handler.commitFilters();
593 }
594 }
595
596 public DispatchingVisitor(Collection targets, VisitorExceptionSink exceptionSink) {
597 this(targets, exceptionSink, null);
598 }
599
600
601
602
603
604 public DispatchingVisitor(Object target, VisitorExceptionSink exceptionSink) {
605 this(Arrays.asList(new Object[] {target}), exceptionSink);
606 }
607
608 public DispatchingVisitor(Object target, VisitorExceptionSink exceptionSink, Listener listener) {
609 this(Arrays.asList(new Object[] {target}), exceptionSink, listener);
610 }
611
612
613
614
615 public Stats getStats() {
616 return stats;
617 }
618
619 public Stats getThreadStats() {
620 Stats ret = (Stats) threadStats.get();
621 return ret;
622 }
623
624 public void leave(Object target) {
625 Iterator lit=listeners.iterator();
626 while (lit.hasNext()) {
627 ((Listener) lit.next()).onLeave(target);
628 }
629
630 if (target!=null) {
631 Iterator it=getLeaveHandlers(target.getClass()).iterator();
632 while (it.hasNext()) {
633 InvocationHandler ih=(InvocationHandler) it.next();
634 Object ret=ih.invoke(target);
635
636 if (ret!=null && ih.returnsValue) {
637 processReturnValue(ih.object, ih.method, target, ret);
638 }
639 }
640
641 it=getFilterHandlers(target.getClass()).iterator();
642 while (it.hasNext()) {
643 ((ApproveInvocationHandler) it.next()).remove(target);
644 }
645 }
646 getVisitorStack().pop(target);
647 }
648
649
650
651
652
653 public void remove(Object target) {
654 Iterator it=handlerList.iterator();
655 while (it.hasNext()) {
656 InvocationHandler h=(InvocationHandler) it.next();
657 if (h.object==target) {
658 h.active=false;
659 }
660 }
661
662 it=leaveHandlerList.iterator();
663 while (it.hasNext()) {
664 InvocationHandler h=(InvocationHandler) it.next();
665 if (h.object==target) {
666 h.active=false;
667 }
668 }
669
670 it=verifyHandlerList.iterator();
671 while (it.hasNext()) {
672 InvocationHandler h=(InvocationHandler) it.next();
673 if (h.object==target) {
674 h.active=false;
675 }
676 }
677 }
678
679
680
681
682
683
684
685 public void execute(Object executionContext) {
686 if (executionContext instanceof Visitable) {
687 ((Visitable) executionContext).accept(this);
688 } else {
689 visit(executionContext);
690 }
691 }
692}
693