Coverage Report - org.apache.tapestry.services.impl.HiveMindExpressionCompiler
 
Classes in this File Line Coverage Branch Coverage Complexity
HiveMindExpressionCompiler
0%
0/200
0%
0/230
9.833
 
 1  
 //Copyright 2004, 2005 The Apache Software Foundation
 2  
 
 3  
 //Licensed under the Apache License, Version 2.0 (the "License");
 4  
 //you may not use this file except in compliance with the License.
 5  
 //You may obtain a copy of the License at
 6  
 
 7  
 //http://www.apache.org/licenses/LICENSE-2.0
 8  
 
 9  
 //Unless required by applicable law or agreed to in writing, software
 10  
 //distributed under the License is distributed on an "AS IS" BASIS,
 11  
 //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  
 //See the License for the specific language governing permissions and
 13  
 //limitations under the License.
 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  
  * Adds to default ognl compiler class pools.
 34  
  *
 35  
  */
 36  
 public class HiveMindExpressionCompiler extends ExpressionCompiler implements OgnlExpressionCompiler {
 37  
 
 38  0
     private static final Log _log = LogFactory.getLog(HiveMindExpressionCompiler.class);
 39  
 
 40  
     private ClassFactory _classFactory;
 41  
 
 42  
     public HiveMindExpressionCompiler(ClassFactory classfactory)
 43  0
     {
 44  0
         _classFactory = classfactory;
 45  0
     }
 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  0
         if (IRender.class.isAssignableFrom(clazz) || clazz.isInterface()
 77  
             || Modifier.isPublic(clazz.getModifiers()))
 78  0
             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  0
         if (context.getRoot() == null)
 114  0
             return null;
 115  
 
 116  0
         Class ret = context.getRoot().getClass();
 117  
 
 118  0
         if (!IRender.class.isInstance(context.getRoot())
 119  
             && context.getFirstAccessor() != null
 120  
             && context.getFirstAccessor().isInstance(context.getRoot()))
 121  
         {
 122  0
             ret = context.getFirstAccessor();
 123  
         }
 124  
 
 125  0
         return ret;
 126  
     }
 127  
 
 128  
     public void compileExpression(OgnlContext context, Node expression, Object root)
 129  
             throws Exception
 130  
     {
 131  0
         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  0
         synchronized (expression)
 136  
         {
 137  0
             if (expression.getAccessor() != null)
 138  0
                 return;
 139  
 
 140  0
             String getBody = null;
 141  
             String setBody;
 142  
             
 143  0
             MethodSignature valueGetter = new MethodSignature(Object.class, "get", new Class[]{OgnlContext.class, Object.class}, null);
 144  0
             MethodSignature valueSetter = new MethodSignature(void.class, "set", new Class[]{OgnlContext.class, Object.class, Object.class}, null);
 145  
 
 146  0
             CompiledExpression compiled = new CompiledExpression(expression, root, valueGetter, valueSetter);
 147  
 
 148  0
             MethodSignature expressionSetter = new MethodSignature(void.class, "setExpression", new Class[]{Node.class}, null);
 149  
 
 150  
             try
 151  
             {
 152  0
                 getBody = generateGetter(context, compiled);
 153  0
             } catch (UnsupportedCompilationException uc)
 154  
             {
 155  
                 // uc.printStackTrace();
 156  
                 // The target object may not fully resolve yet because of a partial tree with a null somewhere, we
 157  
                 // don't want to bail out forever because it might be enhancable on another pass eventually
 158  0
                 return;
 159  0
             } catch (javassist.CannotCompileException e)
 160  
             {
 161  0
                 _log.error("Error generating OGNL getter for expression " + expression + " with root " + root + " and body:\n" + getBody, e);
 162  
 
 163  0
                 e.printStackTrace();
 164  
 
 165  0
                 generateFailSafe(context, expression, root);
 166  0
                 return;
 167  0
             }
 168  
 
 169  
             try
 170  
             {
 171  0
                 generateClassFab(compiled).addMethod(Modifier.PUBLIC, valueGetter, getBody);
 172  0
             } catch (Throwable t)
 173  
             {
 174  0
                 _log.error("Error generating OGNL getter for expression " + expression + " with root " + root + " and body:\n" + getBody, t);
 175  
 
 176  0
                 t.printStackTrace();
 177  
 
 178  0
                 generateFailSafe(context, expression, root);
 179  0
                 return;
 180  0
             }
 181  
 
 182  
             try
 183  
             {
 184  0
                 setBody = generateSetter(context, compiled);
 185  0
             } catch (UnsupportedCompilationException uc)
 186  
             {
 187  
                 //_log.warn("Unsupported setter compilation caught: " + uc.getMessage() + " for expression: " + expression.toString(), uc);
 188  
 
 189  0
                 setBody = generateOgnlSetter(generateClassFab(compiled), valueSetter);
 190  
 
 191  0
                 if (!generateClassFab(compiled).containsMethod(expressionSetter))
 192  
                 {
 193  0
                     generateClassFab(compiled).addField("_node", Node.class);
 194  0
                     generateClassFab(compiled).addMethod(Modifier.PUBLIC, expressionSetter, "{ _node = $1; }");
 195  
                 }
 196  0
             }
 197  
 
 198  
             try
 199  
             {
 200  0
                 if (setBody == null)
 201  
                 {
 202  0
                     setBody = generateOgnlSetter(generateClassFab(compiled), valueSetter);
 203  
 
 204  0
                     if (!generateClassFab(compiled).containsMethod(expressionSetter))
 205  
                     {
 206  0
                         generateClassFab(compiled).addField("_node", Node.class);
 207  0
                         generateClassFab(compiled).addMethod(Modifier.PUBLIC, expressionSetter, "{ _node = $1; }");
 208  
                     }
 209  
                 }
 210  
 
 211  0
                 if (setBody != null)
 212  0
                     generateClassFab(compiled).addMethod(Modifier.PUBLIC, valueSetter, setBody);
 213  
 
 214  0
                 generateClassFab(compiled).addConstructor(new Class[0], new Class[0], "{}");
 215  
 
 216  0
                 Class clazz = ((AbstractFab) generateClassFab(compiled)).createClass(true);
 217  
 
 218  0
                 expression.setAccessor((ExpressionAccessor) clazz.newInstance());
 219  
 
 220  0
             }  catch (Throwable t)
 221  
             {
 222  0
                 _log.error("Error generating OGNL statements for expression " + expression + " with root " + root, t);
 223  0
                 t.printStackTrace();
 224  
 
 225  0
                 generateFailSafe(context, expression, root);
 226  0
                 return;
 227  0
             }
 228  
 
 229  
             // need to set expression on node if the field was just defined.
 230  
 
 231  0
             if (generateClassFab(compiled).containsMethod(expressionSetter))
 232  
             {
 233  0
                 expression.getAccessor().setExpression(expression);
 234  
             }
 235  0
         }
 236  0
     }
 237  
 
 238  
     ClassFab generateClassFab(CompiledExpression compiled)
 239  
             throws Exception
 240  
     {
 241  0
         if (compiled.getGeneratedClass() != null)
 242  0
             return compiled.getGeneratedClass();
 243  
 
 244  0
         ClassFab classFab = _classFactory.newClass(ClassFabUtils.generateClassName(compiled.getExpression().getClass()), Object.class);
 245  0
         classFab.addInterface(ExpressionAccessor.class);
 246  
         
 247  0
         compiled.setGeneratedClass(classFab);
 248  
 
 249  0
         return classFab;
 250  
     }
 251  
 
 252  
     protected void generateFailSafe(OgnlContext context, Node expression, Object root)
 253  
     {
 254  0
         if (expression.getAccessor() != null)
 255  0
             return;
 256  
 
 257  
         try
 258  
         {
 259  0
             ClassFab classFab = _classFactory.newClass(expression.getClass().getName() + expression.hashCode() + "Accessor", Object.class);
 260  0
             classFab.addInterface(ExpressionAccessor.class);
 261  
 
 262  0
             MethodSignature valueGetter = new MethodSignature(Object.class, "get", new Class[]{OgnlContext.class, Object.class}, null);
 263  0
             MethodSignature valueSetter = new MethodSignature(void.class, "set", new Class[]{OgnlContext.class, Object.class, Object.class}, null);
 264  
 
 265  0
             MethodSignature expressionSetter = new MethodSignature(void.class, "setExpression", new Class[]{Node.class}, null);
 266  
 
 267  0
             if (!classFab.containsMethod(expressionSetter))
 268  
             {
 269  0
                 classFab.addField("_node", Node.class);
 270  0
                 classFab.addMethod(Modifier.PUBLIC, expressionSetter, "{ _node = $1; }");
 271  
             }
 272  
 
 273  0
             classFab.addMethod(Modifier.PUBLIC, valueGetter, generateOgnlGetter(classFab, valueGetter));
 274  0
             classFab.addMethod(Modifier.PUBLIC, valueSetter, generateOgnlSetter(classFab, valueSetter));
 275  
 
 276  0
             classFab.addConstructor(new Class[0], new Class[0], "{}");
 277  
 
 278  0
             Class clazz = ((AbstractFab) classFab).createClass(true);
 279  
 
 280  0
             expression.setAccessor((ExpressionAccessor) clazz.newInstance());
 281  
 
 282  
             // need to set expression on node if the field was just defined.
 283  
 
 284  0
             if (classFab.containsMethod(expressionSetter))
 285  
             {
 286  0
                 expression.getAccessor().setExpression(expression);
 287  
             }
 288  
 
 289  0
         } catch (Throwable t)
 290  
         {
 291  0
             t.printStackTrace();
 292  0
         }
 293  0
     }
 294  
 
 295  
     protected String generateGetter(OgnlContext context, CompiledExpression compiled)
 296  
             throws Exception
 297  
     {
 298  0
         String pre = "";
 299  0
         String post = "";
 300  
         String body;
 301  
         String getterCode;
 302  
 
 303  0
         context.setRoot(compiled.getRoot());
 304  0
         context.setCurrentObject(compiled.getRoot());
 305  0
         context.remove(PRE_CAST);
 306  
 
 307  
         try
 308  
         {
 309  0
             getterCode = compiled.getExpression().toGetSourceString(context, compiled.getRoot());
 310  0
         } catch (NullPointerException e)
 311  
         {
 312  0
             if (_log.isDebugEnabled())
 313  0
                 _log.warn("NullPointer caught compiling getter, may be normal ognl method artifact.", e);
 314  
 
 315  0
             throw new UnsupportedCompilationException("Statement threw nullpointer.");
 316  0
         }
 317  
 
 318  0
         if (getterCode == null || getterCode.trim().length() <= 0
 319  
                                   && !ASTVarRef.class.isAssignableFrom(compiled.getExpression().getClass()))
 320  
         {
 321  0
             getterCode = "null";
 322  
         }
 323  
 
 324  0
         String castExpression = (String) context.get(PRE_CAST);
 325  
 
 326  0
         if (context.getCurrentType() == null
 327  
             || context.getCurrentType().isPrimitive()
 328  
             || Character.class.isAssignableFrom(context.getCurrentType())
 329  
             || Object.class == context.getCurrentType())
 330  
         {
 331  0
             pre = pre + " ($w) (";
 332  0
             post = post + ")";
 333  
         }
 334  
 
 335  0
         String rootExpr = !getterCode.equals("null") ? getRootExpression(compiled.getExpression(), compiled.getRoot(), context) : "";
 336  
 
 337  0
         String noRoot = (String) context.remove("_noRoot");
 338  0
         if (noRoot != null)
 339  0
             rootExpr = "";
 340  
 
 341  0
         createLocalReferences(context, generateClassFab(compiled), compiled.getGetterMethod().getParameterTypes());
 342  
 
 343  0
         if (OrderedReturn.class.isInstance(compiled.getExpression()) && ((OrderedReturn) compiled.getExpression()).getLastExpression() != null)
 344  
         {
 345  0
             body = "{ "
 346  
                    + (ASTMethod.class.isInstance(compiled.getExpression()) || ASTChain.class.isInstance(compiled.getExpression()) ? rootExpr : "")
 347  
                    + (castExpression != null ? castExpression : "")
 348  
                    + ((OrderedReturn) compiled.getExpression()).getCoreExpression()
 349  
                    + " return " + pre + ((OrderedReturn) compiled.getExpression()).getLastExpression()
 350  
                    + post
 351  
                    + ";}";
 352  
 
 353  
         } else
 354  
         {
 355  0
             body = "{ return " + pre
 356  
                    + (castExpression != null ? castExpression : "")
 357  
                    + rootExpr
 358  
                    + getterCode
 359  
                    + post
 360  
                    + ";}";
 361  
         }
 362  
 
 363  0
         body = body.replaceAll("\\.\\.", ".");
 364  
 
 365  0
         if (_log.isDebugEnabled())
 366  0
             _log.debug("Getter Body: ===================================\n" + body);
 367  
 
 368  0
         return body;
 369  
     }
 370  
 
 371  
     void createLocalReferences(OgnlContext context, ClassFab classFab, Class[] params)
 372  
             throws CannotCompileException, NotFoundException
 373  
     {
 374  0
         Map referenceMap = context.getLocalReferences();
 375  0
         if (referenceMap == null || referenceMap.size() < 1)
 376  0
             return;
 377  
 
 378  0
         Iterator it = referenceMap.keySet().iterator();
 379  
 
 380  0
         while (it.hasNext())
 381  
         {
 382  0
             String key = (String) it.next();
 383  0
             LocalReference ref = (LocalReference) referenceMap.get(key);
 384  
 
 385  0
             String widener = ref.getType().isPrimitive() ? " " : " ($w) ";
 386  
 
 387  0
             String body = "{";
 388  0
             body += " return  " + widener + ref.getExpression() + ";";
 389  0
             body += "}";
 390  
 
 391  0
             body = body.replaceAll("\\.\\.", ".");
 392  
 
 393  0
             if (_log.isDebugEnabled())
 394  0
                 _log.debug("createLocalReferences() body is:\n" + body);
 395  
 
 396  0
             MethodSignature method = new MethodSignature(ref.getType(), ref.getName(), params, null);
 397  0
             classFab.addMethod(Modifier.PUBLIC, method, body);
 398  
 
 399  0
             it.remove();
 400  0
         }
 401  0
     }
 402  
 
 403  
     protected String generateSetter(OgnlContext context, CompiledExpression compiled)
 404  
             throws Exception
 405  
     {
 406  0
         if (ExpressionNode.class.isInstance(compiled.getExpression())
 407  
             || ASTConst.class.isInstance(compiled.getExpression()))
 408  0
             throw new UnsupportedCompilationException("Can't compile expression/constant setters.");
 409  
 
 410  0
         context.setRoot(compiled.getRoot());
 411  0
         context.setCurrentObject(compiled.getRoot());
 412  0
         context.remove(PRE_CAST);
 413  
 
 414  
         String body;
 415  
 
 416  0
         String setterCode = compiled.getExpression().toSetSourceString(context, compiled.getRoot());
 417  0
         String castExpression = (String) context.get(PRE_CAST);
 418  
 
 419  0
         if (setterCode == null || setterCode.trim().length() < 1)
 420  0
             throw new UnsupportedCompilationException("Can't compile null setter body.");
 421  
 
 422  0
         if (compiled.getRoot() == null)
 423  0
             throw new UnsupportedCompilationException("Can't compile setters with a null root object.");
 424  
 
 425  0
         String pre = getRootExpression(compiled.getExpression(), compiled.getRoot(), context);
 426  
 
 427  0
         String noRoot = (String) context.remove("_noRoot");
 428  0
         if (noRoot != null)
 429  0
             pre = "";
 430  
 
 431  0
         String setterValue = (String) context.remove("setterConversion");
 432  0
         if (setterValue == null)
 433  0
             setterValue = "";
 434  
 
 435  0
         createLocalReferences(context, generateClassFab(compiled), compiled.getSettermethod().getParameterTypes());
 436  
 
 437  0
         body = "{"
 438  
                + setterValue
 439  
                + (castExpression != null ? castExpression : "")
 440  
                + pre
 441  
                + setterCode + ";}";
 442  
 
 443  0
         body = body.replaceAll("\\.\\.", ".");
 444  
 
 445  0
         if (_log.isDebugEnabled())
 446  0
             _log.debug("Setter Body: ===================================\n" + body);
 447  
 
 448  0
         return body;
 449  
     }
 450  
 
 451  
     String generateOgnlGetter(ClassFab newClass, MethodSignature valueGetter)
 452  
             throws Exception
 453  
     {
 454  0
         return "{ return _node.getValue($1, $2); }";
 455  
     }
 456  
 
 457  
     String generateOgnlSetter(ClassFab newClass, MethodSignature valueSetter)
 458  
             throws Exception
 459  
     {
 460  0
         return "{ _node.setValue($1, $2, $3); }";
 461  
     }
 462  
 }