Coverage Report - org.mule.expression.DefaultExpressionManager
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultExpressionManager
0%
0/73
0%
0/34
3
DefaultExpressionManager$1
0%
0/2
N/A
3
DefaultExpressionManager$2
0%
0/7
0%
0/4
3
 
 1  
 /*
 2  
  * $Id: DefaultExpressionManager.java 19500 2010-09-09 17:29:17Z dzapata $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 package org.mule.expression;
 11  
 
 12  
 import org.mule.api.MuleContext;
 13  
 import org.mule.api.MuleMessage;
 14  
 import org.mule.api.context.MuleContextAware;
 15  
 import org.mule.api.expression.ExpressionEvaluator;
 16  
 import org.mule.api.expression.ExpressionManager;
 17  
 import org.mule.api.expression.ExpressionRuntimeException;
 18  
 import org.mule.api.expression.InvalidExpressionException;
 19  
 import org.mule.api.expression.RequiredValueException;
 20  
 import org.mule.api.lifecycle.Disposable;
 21  
 import org.mule.config.i18n.CoreMessages;
 22  
 import org.mule.util.TemplateParser;
 23  
 
 24  
 import java.text.MessageFormat;
 25  
 import java.util.Iterator;
 26  
 
 27  
 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
 28  
 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentMap;
 29  
 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
 30  
 import org.apache.commons.logging.Log;
 31  
 import org.apache.commons.logging.LogFactory;
 32  
 
 33  
 /**
 34  
  * Provides universal access for evaluating expressions embedded in Mule configurations, such  as Xml, Java,
 35  
  * scripting and annotations.
 36  
  * <p/>
 37  
  * Users can register or unregister {@link ExpressionEvaluator} through this interface.
 38  
  */
 39  0
 public class DefaultExpressionManager implements ExpressionManager, MuleContextAware
 40  
 {
 41  
 
 42  
     /**
 43  
      * logger used by this class
 44  
      */
 45  0
     protected static transient final Log logger = LogFactory.getLog(DefaultExpressionManager.class);
 46  
 
 47  
     // default style parser
 48  0
     private TemplateParser parser = TemplateParser.createMuleStyleParser();
 49  
 
 50  0
     private ConcurrentMap evaluators = new ConcurrentHashMap(8);
 51  
 
 52  
     private MuleContext muleContext;
 53  
 
 54  
     public void setMuleContext(MuleContext context)
 55  
     {
 56  0
         this.muleContext = context;
 57  0
     }
 58  
 
 59  
     public void registerEvaluator(ExpressionEvaluator evaluator)
 60  
     {
 61  0
         if (evaluator == null)
 62  
         {
 63  0
             throw new IllegalArgumentException(CoreMessages.objectIsNull("evaluator").getMessage());
 64  
         }
 65  
 
 66  0
         final String name = evaluator.getName();
 67  
         // TODO MULE-3809 Eliminate duplicate evaluators registration
 68  0
         if (logger.isDebugEnabled())
 69  
         {
 70  0
             logger.debug("Evaluators already contain an object named '" + name + "'.  The previous object will be overwritten.");
 71  
         }
 72  0
         evaluators.put(evaluator.getName(), evaluator);
 73  0
     }
 74  
 
 75  
     /**
 76  
      * Checks whether an evaluator is registered with the manager
 77  
      *
 78  
      * @param name the name of the expression evaluator
 79  
      * @return true if the evaluator is registered with the manager, false otherwise
 80  
      */
 81  
     public boolean isEvaluatorRegistered(String name)
 82  
     {
 83  0
         return evaluators.containsKey(name);
 84  
     }
 85  
 
 86  
     /**
 87  
      * Removes the evaluator with the given name
 88  
      *
 89  
      * @param name the name of the evaluator to remove
 90  
      */
 91  
     public ExpressionEvaluator unregisterEvaluator(String name)
 92  
     {
 93  0
         if (name == null)
 94  
         {
 95  0
             return null;
 96  
         }
 97  
 
 98  0
         ExpressionEvaluator evaluator = (ExpressionEvaluator) evaluators.remove(name);
 99  0
         if (evaluator instanceof Disposable)
 100  
         {
 101  0
             ((Disposable) evaluator).dispose();
 102  
         }
 103  0
         return evaluator;
 104  
     }
 105  
 
 106  
     /**
 107  
      * Evaluates the given expression.  The expression should be a single expression definition with or without
 108  
      * enclosing braces. i.e. "mule:serviceName" and "#[mule:serviceName]" are both valid. For situations where
 109  
      * one or more expressions need to be parsed within a single text, the {@link org.mule.api.expression.ExpressionManager#parse(String,org.mule.api.MuleMessage,boolean)}
 110  
      * method should be used since it will iterate through all expressions in a string.
 111  
      *
 112  
      * @param expression a single expression i.e. xpath://foo
 113  
      * @param message    the current message to process.  The expression will evaluata on the message.
 114  
      * @return the result of the evaluation. Expressions that return collection will return an empty collection, not null.
 115  
      * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and
 116  
      *                                    'failIfNull is set to true.
 117  
      */
 118  
     public Object evaluate(String expression, MuleMessage message) throws ExpressionRuntimeException
 119  
     {
 120  0
         return evaluate(expression, message, false);
 121  
     }
 122  
 
 123  
     /**
 124  
      * Evaluates the given expression.  The expression should be a single expression definition with or without
 125  
      * enclosing braces. i.e. "mule:serviceName" and "#[mule:serviceName]" are both valid. For situations where
 126  
      * one or more expressions need to be parsed within a single text, the {@link org.mule.api.expression.ExpressionManager#parse(String,org.mule.api.MuleMessage,boolean)}
 127  
      * method should be used since it will iterate through all expressions in a string.
 128  
      *
 129  
      * @param expression a single expression i.e. xpath://foo
 130  
      * @param message    the current message to process.  The expression will evaluata on the message.
 131  
      * @param failIfNull determines if an exception should be thrown if expression could not be evaluated or returns
 132  
      *                   null.
 133  
      * @return the result of the evaluation.  Expressions that return collection will return an empty collection, not null.
 134  
      * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and
 135  
      *                                    'failIfNull is set to true.
 136  
      */
 137  
     public Object evaluate(String expression, MuleMessage message, boolean failIfNull) throws ExpressionRuntimeException
 138  
     {
 139  
         String name;
 140  
 
 141  0
         if (expression == null)
 142  
         {
 143  0
             throw new IllegalArgumentException(CoreMessages.objectIsNull("expression").getMessage());
 144  
         }
 145  0
         if (expression.startsWith(DEFAULT_EXPRESSION_PREFIX))
 146  
         {
 147  0
             expression = expression.substring(2, expression.length() - 1);
 148  
         }
 149  0
         int i = expression.indexOf(":");
 150  0
         if (i > -1)
 151  
         {
 152  0
             name = expression.substring(0, i);
 153  0
             expression = expression.substring(i + DEFAULT_EXPRESSION_POSTFIX.length());
 154  
         }
 155  
         else
 156  
         {
 157  0
             name = expression;
 158  0
             expression = null;
 159  
         }
 160  0
         return evaluate(expression, name, message, failIfNull);
 161  
     }
 162  
 
 163  
     /**
 164  
      * Evaluates the given expression.  The expression should be a single expression definition with or without
 165  
      * enclosing braces. i.e. "mule:serviceName" and "#[mule:serviceName]" are both valid. For situations where
 166  
      * one or more expressions need to be parsed within a single text, the {@link org.mule.api.expression.ExpressionManager#parse(String,org.mule.api.MuleMessage,boolean)}
 167  
      * method should be used since it will iterate through all expressions in a string.
 168  
      *
 169  
      * @param expression a single expression i.e. xpath://foo
 170  
      * @param evaluator  the evaluator to use when executing the expression
 171  
      * @param message    the current message to process.  The expression will evaluata on the message.
 172  
      * @param failIfNull determines if an exception should be thrown if expression could not be evaluated or returns
 173  
      *                   null or if an exception should be thrown if an empty collection is returned.
 174  
      * @return the result of the evaluation. Expressions that return collection will return an empty collection, not null.
 175  
      * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and
 176  
      *                                    'failIfNull is set to true.
 177  
      */
 178  
     public Object evaluate(String expression, String evaluator, MuleMessage message, boolean failIfNull) throws ExpressionRuntimeException
 179  
     {
 180  0
         ExpressionEvaluator extractor = (ExpressionEvaluator) evaluators.get(evaluator);
 181  0
         if (extractor == null)
 182  
         {
 183  0
             throw new IllegalArgumentException(CoreMessages.expressionEvaluatorNotRegistered(evaluator).getMessage());
 184  
         }
 185  0
         Object result = extractor.evaluate(expression, message);
 186  
         //TODO Handle empty collections || (result instanceof Collection && ((Collection)result).size()==0)
 187  0
         if (failIfNull && (result == null))
 188  
         {
 189  0
             throw new RequiredValueException(CoreMessages.expressionEvaluatorReturnedNull(evaluator, expression));
 190  
         }
 191  0
         if (logger.isDebugEnabled())
 192  
         {
 193  0
             logger.debug(MessageFormat.format("Result of expression: {0}:{1} is: {2}", evaluator, expression, result));
 194  
         }
 195  0
         return result;
 196  
     }
 197  
 
 198  
 
 199  
     /**
 200  
      * Evaluates expressions in a given string. This method will iterate through each expression and evaluate it. If
 201  
      * a user needs to evaluate a single expression they can use {@link org.mule.api.expression.ExpressionManager#evaluate(String,org.mule.api.MuleMessage,boolean)}.
 202  
      *
 203  
      * @param expression a single expression i.e. xpath://foo
 204  
      * @param message    the current message to process.  The expression will evaluata on the message.
 205  
      * @return the result of the evaluation. Expressions that return collection will return an empty collection, not null.
 206  
      * @throws org.mule.api.expression.ExpressionRuntimeException
 207  
      *          if the expression is invalid, or a null is found for the expression and
 208  
      *          'failIfNull is set to true.
 209  
      */
 210  
     public String parse(String expression, MuleMessage message) throws ExpressionRuntimeException
 211  
     {
 212  0
         return parse(expression, message, false);
 213  
     }
 214  
 
 215  
     /**
 216  
      * Evaluates expressions in a given string. This method will iterate through each expression and evaluate it. If
 217  
      * a user needs to evaluate a single expression they can use {@link org.mule.api.expression.ExpressionManager#evaluate(String,org.mule.api.MuleMessage,boolean)}.
 218  
      *
 219  
      * @param expression a single expression i.e. xpath://foo
 220  
      * @param message    the current message to process.  The expression will evaluata on the message.
 221  
      * @param failIfNull determines if an exception should be thrown if expression could not be evaluated or returns null.
 222  
      * @return the result of the evaluation. Expressions that return collection will return an empty collection, not null.
 223  
      * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and
 224  
      *                                    'failIfNull is set to true.
 225  
      */
 226  
     public String parse(final String expression, final MuleMessage message, final boolean failIfNull) throws ExpressionRuntimeException
 227  
     {
 228  0
         return parser.parse(new TemplateParser.TemplateCallback()
 229  0
         {
 230  
             public Object match(String token)
 231  
             {
 232  0
                 return evaluate(token, message, failIfNull);
 233  
             }
 234  
         }, expression);
 235  
     }
 236  
 
 237  
     /**
 238  
      * Clears all registered evaluators from the manager.
 239  
      */
 240  
     public synchronized void clearEvaluators()
 241  
     {
 242  0
         for (Iterator iterator = evaluators.values().iterator(); iterator.hasNext();)
 243  
         {
 244  0
             ExpressionEvaluator evaluator = (ExpressionEvaluator) iterator.next();
 245  0
             if (evaluator instanceof Disposable)
 246  
             {
 247  0
                 ((Disposable) evaluator).dispose();
 248  
             }
 249  0
         }
 250  0
         evaluators.clear();
 251  0
     }
 252  
 
 253  
     public boolean isExpression(String string)
 254  
     {
 255  0
         return (string.contains(DEFAULT_EXPRESSION_PREFIX));
 256  
     }
 257  
 
 258  
     /**
 259  
      * Determines if the expression is valid or not.  This method will validate a single expression or
 260  
      * expressions embedded in a string.  the expression must be well formed i.e. #[bean:user]
 261  
      *
 262  
      * @param expression the expression to validate
 263  
      * @return true if the expression evaluator is recognised
 264  
      */
 265  
     public boolean isValidExpression(String expression)
 266  
     {
 267  
         try
 268  
         {
 269  0
             validateExpression(expression);
 270  0
             return true;
 271  
         }
 272  0
         catch (InvalidExpressionException e)
 273  
         {
 274  0
             logger.warn(e.getMessage());
 275  0
             return false;
 276  
         }
 277  
     }
 278  
 
 279  
     public void validateExpression(String expression) throws InvalidExpressionException
 280  
     {
 281  0
         if (!muleContext.getConfiguration().isValidateExpressions())
 282  
         {
 283  0
             if (logger.isDebugEnabled()) {
 284  0
                 logger.debug("Validate expressions is turned off, no checking done for: " + expression);
 285  
             }
 286  0
             return;
 287  
         }
 288  
         try
 289  
         {
 290  0
             parser.validate(expression);
 291  
         }
 292  0
         catch (IllegalArgumentException e)
 293  
         {
 294  0
             throw new InvalidExpressionException(expression, e.getMessage());
 295  0
         }
 296  
 
 297  0
         final AtomicBoolean valid = new AtomicBoolean(true);
 298  0
         final AtomicBoolean match = new AtomicBoolean(false);
 299  0
         final StringBuffer message = new StringBuffer();
 300  0
         parser.parse(new TemplateParser.TemplateCallback()
 301  0
         {
 302  
             public Object match(String token)
 303  
             {
 304  0
                 match.set(true);
 305  0
                 if (token.indexOf(":") == -1)
 306  
                 {
 307  0
                     if (valid.get())
 308  
                     {
 309  0
                         valid.compareAndSet(true, false);
 310  
                     }
 311  0
                     message.append(token).append(" is invalid\n");
 312  
                 }
 313  0
                 return null;
 314  
             }
 315  
         }, expression);
 316  
 
 317  0
         if (message.length() > 0)
 318  
         {
 319  0
             throw new InvalidExpressionException(expression, message.toString());
 320  
         }
 321  0
         else if(!match.get())
 322  
         {
 323  0
             throw new InvalidExpressionException(expression, "Expression string is not an expression.  Use isExpression(String) to validate first");
 324  
         }
 325  0
     }
 326  
 }