1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.perfectjpattern.core.behavioral.visitor;
22
23 import java.lang.reflect.*;
24 import java.util.*;
25
26 import org.apache.commons.lang.*;
27 import org.perfectjpattern.core.api.behavioral.visitor.*;
28 import org.perfectjpattern.core.extras.delegate.*;
29
30
31
32
33
34
35
36
37
38
39
40
41
42 public abstract
43 class AbstractVisitor<E>
44 implements IVisitor<E>
45 {
46
47
48
49
50
51
52 @SuppressWarnings("unchecked")
53 public final void
54 visit(E anElement)
55 {
56 Validate.notNull(anElement, "'anElement' must not be null");
57
58 String myElementClassName = anElement.getClass().getName();
59
60
61 if (!theLookup.containsKey(myElementClassName))
62 {
63
64 Class myElementType = anElement.getClass();
65 Class myVisitorType = this.getClass();
66
67 Method myMethod = findVisitorMethod(myElementType,
68 myVisitorType, theDelegator);
69
70
71 if (myMethod != null)
72 {
73 theLookup.put(myElementClassName, theDelegator.build(
74 this, myMethod.getName()));
75 }
76 }
77
78
79 if (theLookup.containsKey(myElementClassName))
80 {
81
82 theLookup.get(myElementClassName).visit(anElement);
83 }
84 }
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 @SuppressWarnings("unchecked")
101 public static <E> void
102 reusableVisit(IVisitor<E> aVisitor, E... anElements)
103 throws IllegalArgumentException
104 {
105 Validate.notNull(aVisitor, "'aVisitor' must not be null");
106 Validate.notNull(anElements, "'anElements' must not be null");
107 Validate.notEmpty(anElements, "'anElements' must not be empty.");
108
109 for (E myElement : anElements)
110 {
111
112 Class myElementType = myElement.getClass();
113 Class myVisitorType = aVisitor.getClass();
114
115 VisitorDelegator myDelegator = new VisitorDelegator(IVisitor.class);
116
117 Method myMethod = findVisitorMethod(myElementType, myVisitorType,
118 myDelegator);
119
120
121 if (myMethod != null)
122 {
123 IVisitor<E> myRealVisitor =
124 (IVisitor) myDelegator.build(aVisitor, myMethod.getName());
125
126
127 myRealVisitor.visit(myElement);
128 }
129 }
130 }
131
132
133
134
135
136
137
138 @SuppressWarnings("unchecked")
139 private static
140 class VisitorDelegator<E>
141 extends Delegator<IVisitor<E>>
142 {
143
144
145
146
147
148
149
150 public
151 VisitorDelegator(Class<IVisitor<E>> aClass)
152 {
153 super(aClass);
154 }
155
156
157
158
159
160 @Override
161 protected boolean
162 isSuitableMethod(Method aTestMethod, Class aReturnClass,
163 Class... anArguments)
164 {
165 Class[] myMethodArguments = aTestMethod.getParameterTypes();
166 for (int i = 0; i < myMethodArguments.length; i++)
167 {
168 Class myArgument = myMethodArguments[i];
169
170 if (!anArguments[i].isAssignableFrom(myArgument))
171 {
172 return false;
173 }
174
175 }
176
177 isValidReturn(aTestMethod, aReturnClass);
178
179 return true;
180 }
181
182
183
184
185
186 @Override
187 protected boolean
188 isValidReturn(Method aTestMethod, Class aReturnClass)
189 {
190 return (aReturnClass == null
191 || aTestMethod.getReturnType() == aReturnClass
192 || aTestMethod.getReturnType().equals(aReturnClass)
193 || aTestMethod.getReturnType().isAssignableFrom(aReturnClass));
194 }
195
196
197 @Override
198 public Class
199 getReturn()
200 {
201 return super.getReturn();
202 }
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218 @SuppressWarnings("unchecked")
219 private static Method
220 findVisitorMethod(Class anElementType, Class aVisitorType,
221 VisitorDelegator aDelegator)
222 {
223 Class myReturnClass = aDelegator.getReturn();
224 Method myResult = null;
225 for (Method myMethod : aVisitorType.getMethods())
226 {
227 if (aDelegator.isValidReturn(myMethod, myReturnClass)
228 && Modifier.isPublic(myMethod.getModifiers())
229 && myMethod.getParameterTypes().length == 1
230 && myMethod.getParameterTypes()[0].equals(anElementType))
231 {
232 myResult = myMethod;
233 break;
234 }
235 }
236
237 return myResult;
238 }
239
240
241
242
243
244
245
246
247 private final Map<String, IVisitor<E>> theLookup = new HashMap<String,
248 IVisitor<E>>();
249
250
251
252
253
254 @SuppressWarnings("unchecked")
255 private final VisitorDelegator<E> theDelegator = new VisitorDelegator(
256 IVisitor.class);
257 }