Coverage Report - org.apache.tapestry.services.impl.HiveMindExpressionCompiler
 
Classes in this File Line Coverage Branch Coverage Complexity
HiveMindExpressionCompiler
55% 
49% 
7.75
 
 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  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  
             // must evaluate expression value at least once if object isn't null
 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  
                 // uc.printStackTrace();
 161  
                 // The target object may not fully resolve yet because of a partial tree with a null somewhere, we
 162  
                 // don't want to bail out forever because it might be enhancable on another pass eventually
 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  
                 //_log.warn("Unsupported setter compilation caught: " + uc.getMessage() + " for expression: " + expression.toString(), uc);
 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  
             // need to set expression on node if the field was just defined.
 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  
             // need to set expression on node if the field was just defined.
 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  
 }