1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
|
|
11 |
|
|
12 |
|
|
13 |
|
|
14 |
|
package org.apache.tapestry.services.impl; |
15 |
|
|
16 |
|
import javassist.CannotCompileException; |
17 |
|
import javassist.NotFoundException; |
18 |
|
import ognl.*; |
19 |
|
import ognl.enhance.*; |
20 |
|
import org.apache.commons.logging.Log; |
21 |
|
import org.apache.commons.logging.LogFactory; |
22 |
|
import org.apache.hivemind.service.ClassFab; |
23 |
|
import org.apache.hivemind.service.ClassFabUtils; |
24 |
|
import org.apache.hivemind.service.ClassFactory; |
25 |
|
import org.apache.hivemind.service.MethodSignature; |
26 |
|
import org.apache.tapestry.IRender; |
27 |
|
import org.apache.tapestry.enhance.AbstractFab; |
28 |
|
|
29 |
|
import java.lang.reflect.Modifier; |
30 |
|
import java.util.*; |
31 |
|
|
32 |
|
|
33 |
|
|
34 |
|
|
35 |
|
|
36 |
|
public class HiveMindExpressionCompiler extends ExpressionCompiler implements OgnlExpressionCompiler { |
37 |
|
|
38 |
11 |
private static final Log _log = LogFactory.getLog(HiveMindExpressionCompiler.class); |
39 |
|
|
40 |
|
private ClassFactory _classFactory; |
41 |
|
|
42 |
|
public HiveMindExpressionCompiler(ClassFactory classfactory) |
43 |
17 |
{ |
44 |
17 |
_classFactory = classfactory; |
45 |
17 |
} |
46 |
|
|
47 |
|
public String getClassName(Class clazz) |
48 |
|
{ |
49 |
15 |
if (IRender.class.isAssignableFrom(clazz) || Modifier.isPublic(clazz.getModifiers())) |
50 |
15 |
return clazz.getName(); |
51 |
|
|
52 |
0 |
if (clazz.getName().equals("java.util.AbstractList$Itr")) |
53 |
0 |
return Iterator.class.getName(); |
54 |
|
|
55 |
0 |
if (Modifier.isPublic(clazz.getModifiers()) && clazz.isInterface()) |
56 |
0 |
return clazz.getName(); |
57 |
|
|
58 |
0 |
Class[] intf = clazz.getInterfaces(); |
59 |
|
|
60 |
0 |
for (int i = 0; i < intf.length; i++) { |
61 |
0 |
if (intf[i].getName().indexOf("util.List") > 0) |
62 |
0 |
return intf[i].getName(); |
63 |
0 |
else if (intf[i].getName().indexOf("Iterator") > 0) |
64 |
0 |
return intf[i].getName(); |
65 |
|
} |
66 |
|
|
67 |
0 |
if (clazz.getSuperclass() != null && clazz.getSuperclass().getInterfaces().length > 0) |
68 |
0 |
return getClassName(clazz.getSuperclass()); |
69 |
|
|
70 |
0 |
return clazz.getName(); |
71 |
|
} |
72 |
|
|
73 |
|
public Class getInterfaceClass(Class clazz) |
74 |
|
{ |
75 |
29 |
if (IRender.class.isAssignableFrom(clazz) || clazz.isInterface() |
76 |
|
|| Modifier.isPublic(clazz.getModifiers())) |
77 |
29 |
return clazz; |
78 |
|
|
79 |
0 |
if (clazz.getName().equals("java.util.AbstractList$Itr")) |
80 |
0 |
return Iterator.class; |
81 |
|
|
82 |
0 |
if (Modifier.isPublic(clazz.getModifiers()) |
83 |
|
&& clazz.isInterface() || clazz.isPrimitive()) { |
84 |
|
|
85 |
0 |
return clazz; |
86 |
|
} |
87 |
|
|
88 |
0 |
Class[] intf = clazz.getInterfaces(); |
89 |
|
|
90 |
0 |
for (int i = 0; i < intf.length; i++) { |
91 |
|
|
92 |
0 |
if (List.class.isAssignableFrom(intf[i])) |
93 |
0 |
return List.class; |
94 |
0 |
else if (Iterator.class.isAssignableFrom(intf[i])) |
95 |
0 |
return Iterator.class; |
96 |
0 |
else if (Map.class.isAssignableFrom(intf[i])) |
97 |
0 |
return Map.class; |
98 |
0 |
else if (Set.class.isAssignableFrom(intf[i])) |
99 |
0 |
return Set.class; |
100 |
0 |
else if (Collection.class.isAssignableFrom(intf[i])) |
101 |
0 |
return Collection.class; |
102 |
|
} |
103 |
|
|
104 |
0 |
if (clazz.getSuperclass() != null && clazz.getSuperclass().getInterfaces().length > 0) |
105 |
0 |
return getInterfaceClass(clazz.getSuperclass()); |
106 |
|
|
107 |
0 |
return clazz; |
108 |
|
} |
109 |
|
|
110 |
|
public Class getRootExpressionClass(Node rootNode, OgnlContext context) |
111 |
|
{ |
112 |
15 |
if (context.getRoot() == null) |
113 |
0 |
return null; |
114 |
|
|
115 |
15 |
Class ret = context.getRoot().getClass(); |
116 |
|
|
117 |
15 |
if (!IRender.class.isInstance(context.getRoot()) && context.getFirstAccessor() != null && context.getFirstAccessor().isInstance(context.getRoot())) |
118 |
15 |
ret = context.getFirstAccessor(); |
119 |
|
|
120 |
15 |
return ret; |
121 |
|
} |
122 |
|
|
123 |
|
public void compileExpression(OgnlContext context, Node expression, Object root) |
124 |
|
throws Exception |
125 |
|
{ |
126 |
13 |
if (_log.isDebugEnabled()) |
127 |
0 |
_log.debug("Compiling expr class " + expression.getClass().getName() + " and root " + root.getClass().getName() + " with toString:" + expression.toString()); |
128 |
|
|
129 |
13 |
synchronized (expression) { |
130 |
|
|
131 |
13 |
if (expression.getAccessor() != null) |
132 |
0 |
return; |
133 |
|
|
134 |
13 |
String getBody = null; |
135 |
|
String setBody; |
136 |
|
|
137 |
13 |
ClassFab classFab = _classFactory.newClass(ClassFabUtils.generateClassName(expression.getClass()), Object.class); |
138 |
13 |
classFab.addInterface(ExpressionAccessor.class); |
139 |
|
|
140 |
13 |
MethodSignature valueGetter = new MethodSignature(Object.class, "get", new Class[]{OgnlContext.class, Object.class}, null); |
141 |
13 |
MethodSignature valueSetter = new MethodSignature(void.class, "set", new Class[]{OgnlContext.class, Object.class, Object.class}, null); |
142 |
|
|
143 |
13 |
MethodSignature expressionSetter = new MethodSignature(void.class, "setExpression", new Class[]{Node.class}, null); |
144 |
|
|
145 |
|
|
146 |
|
|
147 |
13 |
if (root != null) |
148 |
13 |
Ognl.getValue(expression, context, root); |
149 |
|
|
150 |
|
try { |
151 |
|
|
152 |
13 |
getBody = generateGetter(context, classFab, valueGetter, expression, root); |
153 |
|
|
154 |
0 |
} catch (UnsupportedCompilationException uc) { |
155 |
|
|
156 |
|
|
157 |
|
|
158 |
|
|
159 |
0 |
return; |
160 |
0 |
} catch (javassist.CannotCompileException e) { |
161 |
|
|
162 |
0 |
_log.error("Error generating OGNL getter for expression " + expression + " with root " + root + " and body:\n" + getBody, e); |
163 |
|
|
164 |
0 |
e.printStackTrace(); |
165 |
|
|
166 |
0 |
generateFailSafe(context, expression, root); |
167 |
0 |
return; |
168 |
13 |
} |
169 |
|
|
170 |
|
try { |
171 |
|
|
172 |
13 |
classFab.addMethod(Modifier.PUBLIC, valueGetter, getBody); |
173 |
|
|
174 |
0 |
} catch (Throwable t) { |
175 |
|
|
176 |
0 |
_log.error("Error generating OGNL getter for expression " + expression + " with root " + root + " and body:\n" + getBody, t); |
177 |
|
|
178 |
0 |
t.printStackTrace(); |
179 |
|
|
180 |
0 |
generateFailSafe(context, expression, root); |
181 |
0 |
return; |
182 |
13 |
} |
183 |
|
|
184 |
|
try { |
185 |
|
|
186 |
13 |
setBody = generateSetter(context, classFab, valueSetter, expression, root); |
187 |
|
|
188 |
6 |
} catch (UnsupportedCompilationException uc) { |
189 |
|
|
190 |
|
|
191 |
|
|
192 |
6 |
setBody = generateOgnlSetter(classFab, valueSetter); |
193 |
|
|
194 |
6 |
if (!classFab.containsMethod(expressionSetter)) { |
195 |
|
|
196 |
6 |
classFab.addField("_node", Node.class); |
197 |
6 |
classFab.addMethod(Modifier.PUBLIC, expressionSetter, "{ _node = $1; }"); |
198 |
|
} |
199 |
7 |
} |
200 |
|
|
201 |
|
try { |
202 |
|
|
203 |
13 |
if (setBody == null) { |
204 |
0 |
setBody = generateOgnlSetter(classFab, valueSetter); |
205 |
|
|
206 |
0 |
if (!classFab.containsMethod(expressionSetter)) { |
207 |
|
|
208 |
0 |
classFab.addField("_node", Node.class); |
209 |
0 |
classFab.addMethod(Modifier.PUBLIC, expressionSetter, "{ _node = $1; }"); |
210 |
|
} |
211 |
|
} |
212 |
|
|
213 |
13 |
if (setBody != null) |
214 |
13 |
classFab.addMethod(Modifier.PUBLIC, valueSetter, setBody); |
215 |
|
|
216 |
13 |
classFab.addConstructor(new Class[0], new Class[0], "{}"); |
217 |
|
|
218 |
13 |
Class clazz = ((AbstractFab) classFab).createClass(true); |
219 |
|
|
220 |
13 |
expression.setAccessor((ExpressionAccessor) clazz.newInstance()); |
221 |
|
|
222 |
0 |
} catch (Throwable t) { |
223 |
|
|
224 |
0 |
_log.error("Error generating OGNL statements for expression " + expression + " with root " + root, t); |
225 |
0 |
t.printStackTrace(); |
226 |
|
|
227 |
0 |
generateFailSafe(context, expression, root); |
228 |
0 |
return; |
229 |
13 |
} |
230 |
|
|
231 |
|
|
232 |
|
|
233 |
13 |
if (classFab.containsMethod(expressionSetter)) { |
234 |
|
|
235 |
6 |
expression.getAccessor().setExpression(expression); |
236 |
|
} |
237 |
|
|
238 |
13 |
} |
239 |
13 |
} |
240 |
|
|
241 |
|
protected void generateFailSafe(OgnlContext context, Node expression, Object root) |
242 |
|
{ |
243 |
0 |
if (expression.getAccessor() != null) |
244 |
0 |
return; |
245 |
|
|
246 |
|
try { |
247 |
0 |
ClassFab classFab = _classFactory.newClass(expression.getClass().getName() + expression.hashCode() + "Accessor", Object.class); |
248 |
0 |
classFab.addInterface(ExpressionAccessor.class); |
249 |
|
|
250 |
0 |
MethodSignature valueGetter = new MethodSignature(Object.class, "get", new Class[]{OgnlContext.class, Object.class}, null); |
251 |
0 |
MethodSignature valueSetter = new MethodSignature(void.class, "set", new Class[]{OgnlContext.class, Object.class, Object.class}, null); |
252 |
|
|
253 |
0 |
MethodSignature expressionSetter = new MethodSignature(void.class, "setExpression", new Class[]{Node.class}, null); |
254 |
|
|
255 |
0 |
if (!classFab.containsMethod(expressionSetter)) { |
256 |
|
|
257 |
0 |
classFab.addField("_node", Node.class); |
258 |
0 |
classFab.addMethod(Modifier.PUBLIC, expressionSetter, "{ _node = $1; }"); |
259 |
|
} |
260 |
|
|
261 |
0 |
classFab.addMethod(Modifier.PUBLIC, valueGetter, generateOgnlGetter(classFab, valueGetter)); |
262 |
0 |
classFab.addMethod(Modifier.PUBLIC, valueSetter, generateOgnlSetter(classFab, valueSetter)); |
263 |
|
|
264 |
0 |
classFab.addConstructor(new Class[0], new Class[0], "{}"); |
265 |
|
|
266 |
0 |
Class clazz = ((AbstractFab) classFab).createClass(true); |
267 |
|
|
268 |
0 |
expression.setAccessor((ExpressionAccessor) clazz.newInstance()); |
269 |
|
|
270 |
|
|
271 |
|
|
272 |
0 |
if (classFab.containsMethod(expressionSetter)) { |
273 |
|
|
274 |
0 |
expression.getAccessor().setExpression(expression); |
275 |
|
} |
276 |
|
|
277 |
0 |
} catch (Throwable t) { |
278 |
|
|
279 |
0 |
t.printStackTrace(); |
280 |
0 |
} |
281 |
0 |
} |
282 |
|
|
283 |
|
protected String generateGetter(OgnlContext context, ClassFab newClass, MethodSignature valueGetter, Node expression, Object root) |
284 |
|
throws Exception |
285 |
|
{ |
286 |
13 |
String pre = ""; |
287 |
13 |
String post = ""; |
288 |
|
String body; |
289 |
|
String getterCode; |
290 |
|
|
291 |
13 |
context.setRoot(root); |
292 |
13 |
context.setCurrentObject(root); |
293 |
13 |
context.remove(PRE_CAST); |
294 |
|
|
295 |
|
try { |
296 |
|
|
297 |
13 |
getterCode = expression.toGetSourceString(context, root); |
298 |
0 |
} catch (NullPointerException e) { |
299 |
0 |
if (_log.isDebugEnabled()) |
300 |
0 |
_log.warn("NullPointer caught compiling getter, may be normal ognl method artifact.", e); |
301 |
|
|
302 |
0 |
throw new UnsupportedCompilationException("Statement threw nullpointer."); |
303 |
13 |
} |
304 |
|
|
305 |
13 |
if (getterCode == null || getterCode.trim().length() <= 0 && !ASTVarRef.class.isAssignableFrom(expression.getClass())) |
306 |
0 |
getterCode = "null"; |
307 |
|
|
308 |
13 |
String castExpression = (String) context.get(PRE_CAST); |
309 |
|
|
310 |
13 |
if (context.getCurrentType() == null |
311 |
|
|| context.getCurrentType().isPrimitive() |
312 |
|
|| Character.class.isAssignableFrom(context.getCurrentType()) |
313 |
|
|| Object.class == context.getCurrentType()) |
314 |
|
{ |
315 |
7 |
pre = pre + " ($w) ("; |
316 |
7 |
post = post + ")"; |
317 |
|
} |
318 |
|
|
319 |
13 |
String rootExpr = !getterCode.equals("null") ? getRootExpression(expression, root, context) : ""; |
320 |
|
|
321 |
13 |
String noRoot = (String) context.remove("_noRoot"); |
322 |
13 |
if (noRoot != null) |
323 |
0 |
rootExpr = ""; |
324 |
|
|
325 |
13 |
createLocalReferences(context, newClass, valueGetter.getParameterTypes()); |
326 |
|
|
327 |
13 |
if (OrderedReturn.class.isInstance(expression) && ((OrderedReturn) expression).getLastExpression() != null) { |
328 |
|
|
329 |
0 |
body = "{ " |
330 |
|
+ (ASTMethod.class.isInstance(expression) || ASTChain.class.isInstance(expression) ? rootExpr : "") |
331 |
|
+ (castExpression != null ? castExpression : "") |
332 |
|
+ ((OrderedReturn) expression).getCoreExpression() |
333 |
|
+ " return " + pre + ((OrderedReturn) expression).getLastExpression() |
334 |
|
+ post |
335 |
|
+ ";}"; |
336 |
|
|
337 |
|
} else { |
338 |
|
|
339 |
13 |
body = "{ return " + pre |
340 |
|
+ (castExpression != null ? castExpression : "") |
341 |
|
+ rootExpr |
342 |
|
+ getterCode |
343 |
|
+ post |
344 |
|
+ ";}"; |
345 |
|
} |
346 |
|
|
347 |
13 |
body = body.replaceAll("\\.\\.", "."); |
348 |
|
|
349 |
13 |
if (_log.isDebugEnabled()) |
350 |
0 |
_log.debug("Getter Body: ===================================\n" + body); |
351 |
|
|
352 |
13 |
return body; |
353 |
|
} |
354 |
|
|
355 |
|
void createLocalReferences(OgnlContext context, ClassFab classFab, Class[] params) |
356 |
|
throws CannotCompileException, NotFoundException |
357 |
|
{ |
358 |
20 |
context.remove(LOCAL_REFERENCE_COUNTER); |
359 |
|
|
360 |
20 |
Map referenceMap = (Map) context.remove(LOCAL_REFERENCE_MAP); |
361 |
20 |
if (referenceMap == null) |
362 |
17 |
return; |
363 |
|
|
364 |
3 |
Iterator it = referenceMap.keySet().iterator(); |
365 |
|
|
366 |
6 |
while (it.hasNext()) { |
367 |
|
|
368 |
3 |
String key = (String) it.next(); |
369 |
3 |
LocalReference ref = (LocalReference) referenceMap.get(key); |
370 |
|
|
371 |
3 |
String widener = ref.getType().isPrimitive() ? " " : " ($w) "; |
372 |
|
|
373 |
3 |
String body = "{"; |
374 |
3 |
body += " return " + widener + ref.getExpression() + ";"; |
375 |
3 |
body += "}"; |
376 |
|
|
377 |
3 |
body = body.replaceAll("\\.\\.", "."); |
378 |
|
|
379 |
3 |
if (_log.isDebugEnabled()) |
380 |
0 |
_log.debug("createLocalReferences() body is:\n" + body); |
381 |
|
|
382 |
3 |
MethodSignature method = new MethodSignature(ref.getType(), ref.getName(), params, null); |
383 |
3 |
classFab.addMethod(Modifier.PUBLIC, method, body); |
384 |
3 |
} |
385 |
3 |
} |
386 |
|
|
387 |
|
protected String generateSetter(OgnlContext context, ClassFab newClass, MethodSignature valueSetter, Node expression, Object root) |
388 |
|
throws Exception |
389 |
|
{ |
390 |
13 |
if (ExpressionNode.class.isInstance(expression) |
391 |
|
|| ASTConst.class.isInstance(expression)) |
392 |
1 |
throw new UnsupportedCompilationException("Can't compile expression/constant setters."); |
393 |
|
|
394 |
12 |
context.setRoot(root); |
395 |
12 |
context.setCurrentObject(root); |
396 |
12 |
context.remove(PRE_CAST); |
397 |
|
|
398 |
|
String body; |
399 |
|
|
400 |
12 |
String setterCode = expression.toSetSourceString(context, root); |
401 |
12 |
String castExpression = (String) context.get(PRE_CAST); |
402 |
|
|
403 |
12 |
if (setterCode == null || setterCode.trim().length() < 1) |
404 |
5 |
throw new UnsupportedCompilationException("Can't compile null setter body."); |
405 |
|
|
406 |
7 |
if (root == null) |
407 |
0 |
throw new UnsupportedCompilationException("Can't compile setters with a null root object."); |
408 |
|
|
409 |
7 |
String pre = getRootExpression(expression, root, context); |
410 |
|
|
411 |
7 |
String noRoot = (String) context.remove("_noRoot"); |
412 |
7 |
if (noRoot != null) |
413 |
0 |
pre = ""; |
414 |
|
|
415 |
7 |
String setterValue = (String) context.remove("setterConversion"); |
416 |
7 |
if (setterValue == null) |
417 |
7 |
setterValue = ""; |
418 |
|
|
419 |
7 |
createLocalReferences(context, newClass, valueSetter.getParameterTypes()); |
420 |
|
|
421 |
7 |
body = "{" |
422 |
|
+ setterValue |
423 |
|
+ (castExpression != null ? castExpression : "") |
424 |
|
+ pre |
425 |
|
+ setterCode + ";}"; |
426 |
|
|
427 |
7 |
body = body.replaceAll("\\.\\.", "."); |
428 |
|
|
429 |
7 |
if (_log.isDebugEnabled()) |
430 |
0 |
_log.debug("Setter Body: ===================================\n" + body); |
431 |
|
|
432 |
7 |
return body; |
433 |
|
} |
434 |
|
|
435 |
|
String generateOgnlGetter(ClassFab newClass, MethodSignature valueGetter) |
436 |
|
throws Exception |
437 |
|
{ |
438 |
0 |
return "{ return _node.getValue($1, $2); }"; |
439 |
|
} |
440 |
|
|
441 |
|
String generateOgnlSetter(ClassFab newClass, MethodSignature valueSetter) |
442 |
|
throws Exception |
443 |
|
{ |
444 |
6 |
return "{ _node.setValue($1, $2, $3); }"; |
445 |
|
} |
446 |
|
} |