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