Coverage Report - org.apache.commons.scxml.env.jsp.ELEvaluator

Classes in this File Line Coverage Branch Coverage Complexity
ELEvaluator
49% 
88% 
4

 1  
 /*
 2  
  *
 3  
  *   Copyright 2005-2006 The Apache Software Foundation.
 4  
  *
 5  
  *  Licensed under the Apache License, Version 2.0 (the "License");
 6  
  *  you may not use this file except in compliance with the License.
 7  
  *  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  *  Unless required by applicable law or agreed to in writing, software
 12  
  *  distributed under the License is distributed on an "AS IS" BASIS,
 13  
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  *  See the License for the specific language governing permissions and
 15  
  *  limitations under the License.
 16  
  *
 17  
  */
 18  
 package org.apache.commons.scxml.env.jsp;
 19  
 
 20  
 import java.lang.reflect.Method;
 21  
 import java.util.Set;
 22  
 import java.util.regex.Pattern;
 23  
 
 24  
 import javax.servlet.jsp.el.ELException;
 25  
 import javax.servlet.jsp.el.ExpressionEvaluator;
 26  
 import javax.servlet.jsp.el.FunctionMapper;
 27  
 import javax.servlet.jsp.el.VariableResolver;
 28  
 
 29  
 import org.apache.commons.el.ExpressionEvaluatorImpl;
 30  
 import org.apache.commons.logging.Log;
 31  
 import org.apache.commons.logging.LogFactory;
 32  
 import org.apache.commons.scxml.Builtin;
 33  
 import org.apache.commons.scxml.Context;
 34  
 import org.apache.commons.scxml.Evaluator;
 35  
 import org.apache.commons.scxml.SCXMLExpressionException;
 36  
 import org.w3c.dom.Node;
 37  
 
 38  
 /**
 39  
  * Evaluator implementation enabling use of EL expressions in
 40  
  * SCXML documents.
 41  
  *
 42  
  */
 43  0
 public class ELEvaluator implements Evaluator {
 44  
 
 45  
     /** Implementation independent log category. */
 46  28
     private Log log = LogFactory.getLog(Evaluator.class);
 47  
     /** Function Mapper for SCXML builtin functions. */
 48  11
     private FunctionMapper builtinFnMapper = new BuiltinFunctionMapper();
 49  
     /** User provided function mapper, we delegate to this mapper if
 50  
         we encounter a function that is not built into SCXML. */
 51  
     private FunctionMapper fnMapper;
 52  
     /** Pattern for recognizing the SCXML In() special predicate. */
 53  3
     private static Pattern inFct = Pattern.compile("In\\(");
 54  
     /** Pattern for recognizing the Commons SCXML Data() builtin function. */
 55  3
     private static Pattern dataFct = Pattern.compile("Data\\(");
 56  
 
 57  
     /** The expression evaluator implementation for the JSP/EL environment. */
 58  11
     private ExpressionEvaluator ee = null;
 59  
 
 60  
     /**
 61  
      * Constructor.
 62  
      */
 63  11
     public ELEvaluator() {
 64  11
         ee = new ExpressionEvaluatorImpl();
 65  11
     }
 66  
 
 67  
     /**
 68  
      * Constructor for EL evaluator that supports user-defined functions.
 69  
      *
 70  
      * @param fnMapper The function mapper for this Evaluator.
 71  
      * @see javax.servlet.jsp.el.FunctionMapper
 72  
      */
 73  0
     public ELEvaluator(final FunctionMapper fnMapper) {
 74  0
         ee = new ExpressionEvaluatorImpl();
 75  0
         this.fnMapper = fnMapper;
 76  0
     }
 77  
 
 78  
     /**
 79  
      * Evaluate an expression.
 80  
      *
 81  
      * @param ctx variable context
 82  
      * @param expr expression
 83  
      * @return a result of the evaluation
 84  
      * @throws SCXMLExpressionException For a malformed expression
 85  
      * @see Evaluator#eval(Context, String)
 86  
      */
 87  
     public Object eval(final Context ctx, final String expr)
 88  
     throws SCXMLExpressionException {
 89  34
         if (expr == null) {
 90  0
             return null;
 91  
         }
 92  34
         VariableResolver vr = null;
 93  34
         if (ctx instanceof VariableResolver) {
 94  34
             vr = (VariableResolver) ctx;
 95  
         } else {
 96  0
             vr = new ContextWrapper(ctx);
 97  
         }
 98  
         try {
 99  34
             String evalExpr = inFct.matcher(expr).
 100  
                 replaceAll("In(_ALL_STATES, ");
 101  34
             Object rslt = ee.evaluate(evalExpr, Object.class, vr,
 102  
                 builtinFnMapper);
 103  34
             if (log.isTraceEnabled()) {
 104  0
                 log.trace(expr + " = " + String.valueOf(rslt));
 105  
             }
 106  34
             return rslt;
 107  0
         } catch (ELException e) {
 108  0
             throw new SCXMLExpressionException(e);
 109  
         }
 110  
     }
 111  
 
 112  
     /**
 113  
      * @see Evaluator#evalCond(Context, String)
 114  
      */
 115  
     public Boolean evalCond(final Context ctx, final String expr)
 116  
     throws SCXMLExpressionException {
 117  28
         if (expr == null) {
 118  0
             return null;
 119  
         }
 120  28
         VariableResolver vr = null;
 121  28
         if (ctx instanceof VariableResolver) {
 122  28
             vr = (VariableResolver) ctx;
 123  
         } else {
 124  0
             vr = new ContextWrapper(ctx);
 125  
         }
 126  
         try {
 127  28
             String evalExpr = inFct.matcher(expr).
 128  
                 replaceAll("In(_ALL_STATES, ");
 129  28
             Boolean rslt = (Boolean) ee.evaluate(evalExpr, Boolean.class,
 130  
                 vr, builtinFnMapper);
 131  28
             if (log.isDebugEnabled()) {
 132  0
                 log.debug(expr + " = " + String.valueOf(rslt));
 133  
             }
 134  28
             return rslt;
 135  0
         } catch (ELException e) {
 136  0
             throw new SCXMLExpressionException(e);
 137  
         }
 138  
     }
 139  
 
 140  
     /**
 141  
      * @see Evaluator#evalLocation(Context, String)
 142  
      */
 143  
     public Node evalLocation(final Context ctx, final String expr)
 144  
     throws SCXMLExpressionException {
 145  12
         if (expr == null) {
 146  0
             return null;
 147  
         }
 148  12
         VariableResolver vr = null;
 149  12
         if (ctx instanceof VariableResolver) {
 150  12
             vr = (VariableResolver) ctx;
 151  
         } else {
 152  0
             vr = new ContextWrapper(ctx);
 153  
         }
 154  
         try {
 155  12
             String evalExpr = inFct.matcher(expr).
 156  
                 replaceAll("In(_ALL_STATES, ");
 157  12
             evalExpr = dataFct.matcher(evalExpr).
 158  
                 replaceFirst("LData(");
 159  12
             Node rslt = (Node) ee.evaluate(evalExpr, Node.class,
 160  
                 vr, builtinFnMapper);
 161  8
             if (log.isDebugEnabled()) {
 162  0
                 log.debug(expr + " = " + String.valueOf(rslt));
 163  
             }
 164  8
             return rslt;
 165  4
         } catch (ELException e) {
 166  4
             throw new SCXMLExpressionException(e);
 167  
         }
 168  
     }
 169  
 
 170  
     /**
 171  
      * Create a new child context.
 172  
      *
 173  
      * @param parent parent context
 174  
      * @return new child context
 175  
      * @see Evaluator#newContext(Context)
 176  
      */
 177  
     public Context newContext(final Context parent) {
 178  45
         return new ELContext(parent);
 179  
     }
 180  
 
 181  
     /**
 182  
      * Set the log used by this <code>Evaluator</code> instance.
 183  
      *
 184  
      * @param log The new log.
 185  
      */
 186  
     protected void setLog(final Log log) {
 187  0
         this.log = log;
 188  0
     }
 189  
 
 190  
     /**
 191  
      * Get the log used by this <code>Evaluator</code> instance.
 192  
      *
 193  
      * @return Log The log being used.
 194  
      */
 195  
     protected Log getLog() {
 196  0
         return log;
 197  
     }
 198  
 
 199  
     /**
 200  
      * A Context wrapper that implements VariableResolver.
 201  
      */
 202  
     static class ContextWrapper implements VariableResolver {
 203  
         /** Context to be wrapped. */
 204  0
         private Context ctx = null;
 205  
         /** The log. */
 206  0
         private Log log = LogFactory.getLog(ContextWrapper.class);
 207  
         /**
 208  
          * Constructor.
 209  
          * @param ctx The Context to be wrapped.
 210  
          */
 211  0
         ContextWrapper(final Context ctx) {
 212  0
             this.ctx = ctx;
 213  0
         }
 214  
         /** @see VariableResolver#resolveVariable(String) */
 215  
         public Object resolveVariable(final String pName) throws ELException {
 216  0
             Object rslt = ctx.get(pName);
 217  0
             if (rslt == null) {
 218  0
                 log.info("Variable \"" + pName + "\" does not exist!");
 219  
             }
 220  0
             return rslt;
 221  
         }
 222  
     }
 223  
 
 224  
     /**
 225  
      * A simple function mapper for SCXML defined functions.
 226  
      */
 227  11
     class BuiltinFunctionMapper implements FunctionMapper {
 228  
         /** The log. */
 229  11
         private Log log = LogFactory.getLog(BuiltinFunctionMapper.class);
 230  
         /**
 231  
          * @see FunctionMapper#resolveFunction(String, String)
 232  
          */
 233  
         public Method resolveFunction(final String prefix,
 234  
                 final String localName) {
 235  16
             if (localName.equals("In")) {
 236  2
                 Class[] attrs = new Class[] {Set.class, String.class};
 237  
                 try {
 238  2
                     return Builtin.class.getMethod("isMember", attrs);
 239  0
                 } catch (SecurityException e) {
 240  0
                     log.error("resolving isMember(Set, String)", e);
 241  0
                 } catch (NoSuchMethodException e) {
 242  0
                     log.error("resolving isMember(Set, String)", e);
 243  0
                 }
 244  14
             } else if (localName.equals("Data")) {
 245  
                 // rvalue in expressions, coerce to String
 246  6
                 Class[] attrs = new Class[] {Object.class, String.class};
 247  
                 try {
 248  6
                     return Builtin.class.getMethod("data", attrs);
 249  0
                 } catch (SecurityException e) {
 250  0
                     log.error("resolving data(Node, String)", e);
 251  0
                 } catch (NoSuchMethodException e) {
 252  0
                     log.error("resolving data(Node, String)", e);
 253  0
                 }
 254  8
             } else if (localName.equals("LData")) {
 255  
                 // lvalue in expressions, retain as Node
 256  8
                 Class[] attrs = new Class[] {Object.class, String.class};
 257  
                 try {
 258  8
                     return Builtin.class.getMethod("dataNode", attrs);
 259  0
                 } catch (SecurityException e) {
 260  0
                     log.error("resolving data(Node, String)", e);
 261  0
                 } catch (NoSuchMethodException e) {
 262  0
                     log.error("resolving data(Node, String)", e);
 263  0
                 }
 264  0
             } else if (fnMapper != null) {
 265  0
                 return fnMapper.resolveFunction(prefix, localName);
 266  
             }
 267  0
             return null;
 268  
         }
 269  
     }
 270  
 
 271  
     /**
 272  
      * Get the FunctionMapper for builtin SCXML/Commons SCXML functions.
 273  
      *
 274  
      * @return builtinFnMapper The FunctionMapper
 275  
      */
 276  
     protected FunctionMapper getBuiltinFnMapper() {
 277  0
         return builtinFnMapper;
 278  
     }
 279  
 
 280  
 }
 281