1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.javagen.agile.core.visitor;
17
18 import java.util.HashMap;
19 import java.util.Map;
20
21 import org.javagen.agile.core.model.Model;
22
23 /***
24 * Defines a generic, extensible visitor pattern based on registering a
25 * <code>Visit</code> instance for each <code>Model</code> type.
26 * <p>
27 * The biggest problem with the traditional visitor pattern is that it binds you to a
28 * fixed set of node types witch is not good in an open-ended framework
29 * like JavaGen-Agile. This visitor pattern avoids that by allowing any number
30 * of <code>Visit</code> methods to be registered by <code>Model</code> type.
31 * <p>
32 * Arbitrary model hierarchies can be combined as this example illustrates:
33 * <pre>
34 * Visitor visitor = new TypeLookupVisitor( new OOLookupVisitor(), new DBLookupVisitor() );
35 * visitor.visit( combinedModelTree );
36 * </pre>
37 *
38 * @author Richard Easterling
39 */
40 public class TypeLookupVisitor extends DefaultVisitor {
41
42 @SuppressWarnings("unchecked")
43 protected Map<Class, Visit> visitInstances = new HashMap<Class, Visit>();
44
45 protected Visit defualtVisit;
46
47 public TypeLookupVisitor() {}
48
49 public TypeLookupVisitor(TypeLookupVisitor[] lookupVisitorDelegates) {
50 for(TypeLookupVisitor lookupVisitor : lookupVisitorDelegates)
51 this.addVisitInstances(lookupVisitor.getVisitInstances());
52 }
53
54
55
56
57
58 /***
59 * Lookup Visit instance for this model type and invoke <code>visit</code> method.
60 * If no <code>Visit</code> instance is registered for a given type, the <code>defaultVisit</code>
61 * method will be invoked if one has been specified.
62 * <p>
63 * Note: this method is only called if there is either no itinerary or the itinerary includes
64 * this <code>modelType</code>.
65 */
66 public void visit(Model model) {
67 Visit visit = get(model.getClass());
68 if (visit!=null) {
69 visit.visit(model);
70 } else {
71 if (defualtVisit!=null)
72 defualtVisit.visit(model);
73 }
74 }
75
76
77
78
79
80 @SuppressWarnings("unchecked")
81 public void addVisitInstances(Map<Class, Visit> visitInstances) {
82 for(Map.Entry<Class,Visit> entry : visitInstances.entrySet())
83 put(entry.getKey(), entry.getValue());
84 }
85
86 @SuppressWarnings("unchecked")
87 public void put(Class clazz, Visit visit) {
88 if (clazz.equals(Model.class)) {
89 defualtVisit = visit;
90 } else {
91 visitInstances.put(clazz, visit);
92 }
93 }
94
95 @SuppressWarnings("unchecked")
96 public Visit get(Class clazz) {
97 return this.visitInstances.get(clazz);
98 }
99
100 @SuppressWarnings("unchecked")
101 public Map<Class, Visit> getVisitInstances() {
102 return visitInstances;
103 }
104
105 @SuppressWarnings("unchecked")
106 public void setVisitInstances(Map<Class, Visit> visitInstances) {
107 this.visitInstances = visitInstances;
108 }
109
110 public Visit getDefualtVisit() {
111 return defualtVisit;
112 }
113
114 public void setDefualtVisit(Visit defualtVisit) {
115 this.defualtVisit = defualtVisit;
116 }
117 }