Coverage Report - org.mule.expression.DefaultExpressionManager
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultExpressionManager
0%
0/132
0%
0/64
3.308
DefaultExpressionManager$1
0%
0/5
0%
0/2
3.308
DefaultExpressionManager$2
0%
0/7
0%
0/4
3.308
 
 1  
 /*
 2  
  * $Id: DefaultExpressionManager.java 20441 2010-12-02 16:15:09Z dfeist $
 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.ExpressionEnricher;
 16  
 import org.mule.api.expression.ExpressionEvaluator;
 17  
 import org.mule.api.expression.ExpressionManager;
 18  
 import org.mule.api.expression.ExpressionRuntimeException;
 19  
 import org.mule.api.expression.InvalidExpressionException;
 20  
 import org.mule.api.expression.RequiredValueException;
 21  
 import org.mule.api.lifecycle.Disposable;
 22  
 import org.mule.config.i18n.CoreMessages;
 23  
 import org.mule.util.TemplateParser;
 24  
 
 25  
 import java.text.MessageFormat;
 26  
 import java.util.Iterator;
 27  
 
 28  
 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
 29  
 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentMap;
 30  
 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
 31  
 
 32  
 import org.apache.commons.logging.Log;
 33  
 import org.apache.commons.logging.LogFactory;
 34  
 
 35  
 /**
 36  
  * Provides universal access for evaluating expressions embedded in Mule configurations, such  as Xml, Java,
 37  
  * scripting and annotations.
 38  
  * <p/>
 39  
  * Users can register or unregister {@link ExpressionEvaluator} through this interface.
 40  
  */
 41  0
 public class DefaultExpressionManager implements ExpressionManager, MuleContextAware
 42  
 {
 43  
 
 44  
     /**
 45  
      * logger used by this class
 46  
      */
 47  0
     protected static transient final Log logger = LogFactory.getLog(DefaultExpressionManager.class);
 48  
 
 49  
     // default style parser
 50  0
     private TemplateParser parser = TemplateParser.createMuleStyleParser();
 51  
 
 52  0
     private ConcurrentMap evaluators = new ConcurrentHashMap(8);
 53  0
     private ConcurrentMap enrichers = new ConcurrentHashMap(8);
 54  
 
 55  
     private MuleContext muleContext;
 56  
 
 57  
     public void setMuleContext(MuleContext context)
 58  
     {
 59  0
         this.muleContext = context;
 60  0
     }
 61  
 
 62  
     public void registerEvaluator(ExpressionEvaluator evaluator)
 63  
     {
 64  0
         if (evaluator == null)
 65  
         {
 66  0
             throw new IllegalArgumentException(CoreMessages.objectIsNull("evaluator").getMessage());
 67  
         }
 68  
 
 69  0
         final String name = evaluator.getName();
 70  
         // TODO MULE-3809 Eliminate duplicate evaluators registration
 71  0
         if (logger.isDebugEnabled())
 72  
         {
 73  0
             logger.debug("Evaluators already contain an object named '" + name + "'.  The previous object will be overwritten.");
 74  
         }
 75  0
         evaluators.put(evaluator.getName(), evaluator);
 76  0
     }
 77  
 
 78  
     public void registerEnricher(ExpressionEnricher enricher)
 79  
     {
 80  0
         if (enricher == null)
 81  
         {
 82  0
             throw new IllegalArgumentException(CoreMessages.objectIsNull("enricher").getMessage());
 83  
         }
 84  
 
 85  0
         final String name = enricher.getName();
 86  
         // TODO MULE-3809 Eliminate duplicate evaluators registration
 87  0
         if (logger.isDebugEnabled())
 88  
         {
 89  0
             logger.debug("Enrichers already contain an object named '" + name + "'.  The previous object will be overwritten.");
 90  
         }
 91  0
         enrichers.put(enricher.getName(), enricher);
 92  0
     }
 93  
 
 94  
     /**
 95  
      * Checks whether an evaluator is registered with the manager
 96  
      *
 97  
      * @param name the name of the expression evaluator
 98  
      * @return true if the evaluator is registered with the manager, false otherwise
 99  
      */
 100  
     public boolean isEvaluatorRegistered(String name)
 101  
     {
 102  0
         return evaluators.containsKey(name);
 103  
     }
 104  
     
 105  
     /**
 106  
      * Checks whether an enricher is registered with the manager
 107  
      *
 108  
      * @param name the name of the expression enricher
 109  
      * @return true if the enricher is registered with the manager, false otherwise
 110  
      */
 111  
     public boolean isEnricherRegistered(String name)
 112  
     {
 113  0
         return enrichers.containsKey(name);
 114  
     }
 115  
     
 116  
     /**
 117  
      * Removes the evaluator with the given name
 118  
      *
 119  
      * @param name the name of the evaluator to remove
 120  
      */
 121  
     public ExpressionEvaluator unregisterEvaluator(String name)
 122  
     {
 123  0
         if (name == null)
 124  
         {
 125  0
             return null;
 126  
         }
 127  
 
 128  0
         ExpressionEvaluator evaluator = (ExpressionEvaluator) evaluators.remove(name);
 129  0
         if (evaluator instanceof Disposable)
 130  
         {
 131  0
             ((Disposable) evaluator).dispose();
 132  
         }
 133  0
         return evaluator;
 134  
     }
 135  
     
 136  
     /**
 137  
      * Removes the evaluator with the given name
 138  
      *
 139  
      * @param name the name of the evaluator to remove
 140  
      */
 141  
     public ExpressionEnricher unregisterEnricher(String name)
 142  
     {
 143  0
         if (name == null)
 144  
         {
 145  0
             return null;
 146  
         }
 147  
 
 148  0
         ExpressionEnricher enricher = (ExpressionEnricher) enrichers.remove(name);
 149  0
         if (enricher instanceof Disposable)
 150  
         {
 151  0
             ((Disposable) enricher).dispose();
 152  
         }
 153  0
         return enricher;
 154  
     }
 155  
 
 156  
     /**
 157  
      * Evaluates the given expression.  The expression should be a single expression definition with or without
 158  
      * enclosing braces. i.e. "mule:serviceName" and "#[mule:serviceName]" are both valid. For situations where
 159  
      * 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)}
 160  
      * method should be used since it will iterate through all expressions in a string.
 161  
      *
 162  
      * @param expression a single expression i.e. xpath://foo
 163  
      * @param message    the current message to process.  The expression will evaluata on the message.
 164  
      * @return the result of the evaluation. Expressions that return collection will return an empty collection, not null.
 165  
      * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and
 166  
      *                                    'failIfNull is set to true.
 167  
      */
 168  
     public Object evaluate(String expression, MuleMessage message) throws ExpressionRuntimeException
 169  
     {
 170  0
         return evaluate(expression, message, false);
 171  
     }
 172  
 
 173  
     /**
 174  
      * Evaluates the given expression.  The expression should be a single expression definition with or without
 175  
      * enclosing braces. i.e. "mule:serviceName" and "#[mule:serviceName]" are both valid. For situations where
 176  
      * 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)}
 177  
      * method should be used since it will iterate through all expressions in a string.
 178  
      *
 179  
      * @param expression a single expression i.e. xpath://foo
 180  
      * @param message    the current message to process.  The expression will evaluata on the message.
 181  
      * @param failIfNull determines if an exception should be thrown if expression could not be evaluated or returns
 182  
      *                   null.
 183  
      * @return the result of the evaluation.  Expressions that return collection will return an empty collection, not null.
 184  
      * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and
 185  
      *                                    'failIfNull is set to true.
 186  
      */
 187  
     public Object evaluate(String expression, MuleMessage message, boolean failIfNull) throws ExpressionRuntimeException
 188  
     {
 189  
         String name;
 190  
 
 191  0
         if (expression == null)
 192  
         {
 193  0
             throw new IllegalArgumentException(CoreMessages.objectIsNull("expression").getMessage());
 194  
         }
 195  0
         if (expression.startsWith(DEFAULT_EXPRESSION_PREFIX))
 196  
         {
 197  0
             expression = expression.substring(2, expression.length() - 1);
 198  
         }
 199  0
         int i = expression.indexOf(":");
 200  0
         if (i > -1)
 201  
         {
 202  0
             name = expression.substring(0, i);
 203  0
             expression = expression.substring(i + DEFAULT_EXPRESSION_POSTFIX.length());
 204  
         }
 205  
         else
 206  
         {
 207  0
             name = expression;
 208  0
             expression = null;
 209  
         }
 210  0
         return evaluate(expression, name, message, failIfNull);
 211  
     }
 212  
 
 213  
 
 214  
     public void enrich(String expression, MuleMessage message, Object object)
 215  
         throws ExpressionRuntimeException
 216  
     {
 217  
         String enricherName;
 218  
 
 219  0
         if (expression == null)
 220  
         {
 221  0
             throw new IllegalArgumentException(CoreMessages.objectIsNull("expression").getMessage());
 222  
         }
 223  0
         if (expression.startsWith(DEFAULT_EXPRESSION_PREFIX))
 224  
         {
 225  0
             expression = expression.substring(2, expression.length() - 1);
 226  
         }
 227  0
         int i = expression.indexOf(":");
 228  0
         if (i > -1)
 229  
         {
 230  0
             enricherName = expression.substring(0, i);
 231  0
             expression = expression.substring(i + DEFAULT_EXPRESSION_POSTFIX.length());
 232  
         }
 233  
         else
 234  
         {
 235  0
             enricherName = expression;
 236  0
             expression = null;
 237  
         }
 238  0
         enrich(expression, enricherName, message, object);
 239  0
     }
 240  
 
 241  
     public void enrich(String expression, String enricherName, MuleMessage message, Object object)
 242  
     {
 243  0
         ExpressionEnricher enricher = (ExpressionEnricher) enrichers.get(enricherName);
 244  0
         if (enricher == null)
 245  
         {
 246  0
             throw new IllegalArgumentException(CoreMessages.expressionEnricherNotRegistered(enricherName)
 247  
                 .getMessage());
 248  
         }
 249  0
         enricher.enrich(expression, message, object);
 250  0
     }
 251  
 
 252  
     /**
 253  
      * Evaluates the given expression.  The expression should be a single expression definition with or without
 254  
      * enclosing braces. i.e. "mule:serviceName" and "#[mule:serviceName]" are both valid. For situations where
 255  
      * 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)}
 256  
      * method should be used since it will iterate through all expressions in a string.
 257  
      *
 258  
      * @param expression a single expression i.e. xpath://foo
 259  
      * @param evaluator  the evaluator to use when executing the expression
 260  
      * @param message    the current message to process.  The expression will evaluata on the message.
 261  
      * @param failIfNull determines if an exception should be thrown if expression could not be evaluated or returns
 262  
      *                   null or if an exception should be thrown if an empty collection is returned.
 263  
      * @return the result of the evaluation. Expressions that return collection will return an empty collection, not null.
 264  
      * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and
 265  
      *                                    'failIfNull is set to true.
 266  
      */
 267  
     public Object evaluate(String expression, String evaluator, MuleMessage message, boolean failIfNull) throws ExpressionRuntimeException
 268  
     {
 269  0
         ExpressionEvaluator extractor = (ExpressionEvaluator) evaluators.get(evaluator);
 270  0
         if (extractor == null)
 271  
         {
 272  0
             throw new IllegalArgumentException(CoreMessages.expressionEvaluatorNotRegistered(evaluator).getMessage());
 273  
         }
 274  0
         Object result = extractor.evaluate(expression, message);
 275  
         //TODO Handle empty collections || (result instanceof Collection && ((Collection)result).size()==0)
 276  0
         if (failIfNull && (result == null))
 277  
         {
 278  0
             throw new RequiredValueException(CoreMessages.expressionEvaluatorReturnedNull(evaluator, expression));
 279  
         }
 280  0
         if (logger.isDebugEnabled())
 281  
         {
 282  0
             logger.debug(MessageFormat.format("Result of expression: {0}:{1} is: {2}", evaluator, expression, result));
 283  
         }
 284  0
         return result;
 285  
     }
 286  
 
 287  
     public boolean evaluateBoolean(String expression, String evaluator, MuleMessage message)
 288  
         throws ExpressionRuntimeException
 289  
     {
 290  0
         return evaluateBoolean(expression, evaluator, message, false, false);
 291  
     }
 292  
 
 293  
     public boolean evaluateBoolean(String expression, MuleMessage message) throws ExpressionRuntimeException
 294  
     {
 295  0
         return evaluateBoolean(expression, message, false, false);
 296  
     }
 297  
 
 298  
     public boolean evaluateBoolean(String expression,
 299  
                                    String evaluator,
 300  
                                    MuleMessage message,
 301  
                                    boolean nullReturnsTrue,
 302  
                                    boolean nonBooleanReturnsTrue) throws ExpressionRuntimeException
 303  
     {
 304  
         try
 305  
         {
 306  0
             return resolveBoolean(evaluate(expression, evaluator, message, false), nullReturnsTrue,
 307  
                 nonBooleanReturnsTrue, expression);
 308  
         }
 309  0
         catch (RequiredValueException e)
 310  
         {
 311  0
             return nullReturnsTrue;
 312  
         }
 313  
     }
 314  
 
 315  
     public boolean evaluateBoolean(String expression,
 316  
                                    MuleMessage message,
 317  
                                    boolean nullReturnsTrue,
 318  
                                    boolean nonBooleanReturnsTrue) throws ExpressionRuntimeException
 319  
     {
 320  
         try
 321  
         {
 322  0
             return resolveBoolean(evaluate(expression, message, false), nullReturnsTrue,
 323  
                 nonBooleanReturnsTrue, expression);
 324  
         }
 325  0
         catch (RequiredValueException e)
 326  
         {
 327  0
             return nullReturnsTrue;
 328  
         }
 329  
     }
 330  
 
 331  
     protected boolean resolveBoolean(Object result,
 332  
                                      boolean nullReturnsTrue,
 333  
                                      boolean nonBooleanReturnsTrue,
 334  
                                      String expression)
 335  
     {
 336  0
         if (result == null)
 337  
         {
 338  0
             return nullReturnsTrue;
 339  
         }
 340  0
         else if (result instanceof Boolean)
 341  
         {
 342  0
             return (Boolean) result;
 343  
         }
 344  0
         else if (result instanceof String)
 345  
         {
 346  0
             if (result.toString().toLowerCase().equalsIgnoreCase("false"))
 347  
             {
 348  0
                 return false;
 349  
             }
 350  0
             else if (result.toString().toLowerCase().equalsIgnoreCase("true"))
 351  
             {
 352  0
                 return true;
 353  
             }
 354  
             else
 355  
             {
 356  0
                 return nonBooleanReturnsTrue;
 357  
             }
 358  
         }
 359  
         else
 360  
         {
 361  0
             logger.warn("Expression: " + expression + ", returned an non-boolean result. Returning: "
 362  
                         + nonBooleanReturnsTrue);
 363  0
             return nonBooleanReturnsTrue;
 364  
         }
 365  
     }
 366  
 
 367  
     /**
 368  
      * Evaluates expressions in a given string. This method will iterate through each expression and evaluate it. If
 369  
      * a user needs to evaluate a single expression they can use {@link org.mule.api.expression.ExpressionManager#evaluate(String,org.mule.api.MuleMessage,boolean)}.
 370  
      *
 371  
      * @param expression a single expression i.e. xpath://foo
 372  
      * @param message    the current message to process.  The expression will evaluata on the message.
 373  
      * @return the result of the evaluation. Expressions that return collection will return an empty collection, not null.
 374  
      * @throws org.mule.api.expression.ExpressionRuntimeException
 375  
      *          if the expression is invalid, or a null is found for the expression and
 376  
      *          'failIfNull is set to true.
 377  
      */
 378  
     public String parse(String expression, MuleMessage message) throws ExpressionRuntimeException
 379  
     {
 380  0
         return parse(expression, message, false);
 381  
     }
 382  
 
 383  
     /**
 384  
      * Evaluates expressions in a given string. This method will iterate through each expression and evaluate it. If
 385  
      * a user needs to evaluate a single expression they can use {@link org.mule.api.expression.ExpressionManager#evaluate(String,org.mule.api.MuleMessage,boolean)}.
 386  
      *
 387  
      * @param expression a single expression i.e. xpath://foo
 388  
      * @param message    the current message to process.  The expression will evaluata on the message.
 389  
      * @param failIfNull determines if an exception should be thrown if expression could not be evaluated or returns null.
 390  
      * @return the result of the evaluation. Expressions that return collection will return an empty collection, not null.
 391  
      * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and
 392  
      *                                    'failIfNull is set to true.
 393  
      */
 394  
     public String parse(final String expression, final MuleMessage message, final boolean failIfNull) throws ExpressionRuntimeException
 395  
     {
 396  0
         return parser.parse(new TemplateParser.TemplateCallback()
 397  0
         {
 398  
             public Object match(String token)
 399  
             {
 400  0
                 Object result = evaluate(token, message, failIfNull);
 401  0
                 if (result instanceof MuleMessage)
 402  
                 {
 403  0
                     return ((MuleMessage) result).getPayload();
 404  
                 }
 405  
                 else
 406  
                 {
 407  0
                     return result;
 408  
                 }
 409  
             }
 410  
         }, expression);
 411  
     }
 412  
 
 413  
     /**
 414  
      * Clears all registered evaluators from the manager.
 415  
      */
 416  
     public synchronized void clearEvaluators()
 417  
     {
 418  0
         for (Iterator iterator = evaluators.values().iterator(); iterator.hasNext();)
 419  
         {
 420  0
             ExpressionEvaluator evaluator = (ExpressionEvaluator) iterator.next();
 421  0
             if (evaluator instanceof Disposable)
 422  
             {
 423  0
                 ((Disposable) evaluator).dispose();
 424  
             }
 425  0
         }
 426  0
         evaluators.clear();
 427  0
     }
 428  
     
 429  
     public void clearEnrichers()
 430  
     {
 431  0
         for (Iterator iterator = enrichers.values().iterator(); iterator.hasNext();)
 432  
         {
 433  0
             ExpressionEnricher enricher = (ExpressionEnricher) iterator.next();
 434  0
             if (enricher instanceof Disposable)
 435  
             {
 436  0
                 ((Disposable) enricher).dispose();
 437  
             }
 438  0
         }
 439  0
         enrichers.clear();
 440  0
     }
 441  
 
 442  
     public boolean isExpression(String string)
 443  
     {
 444  0
         return (string.contains(DEFAULT_EXPRESSION_PREFIX));
 445  
     }
 446  
 
 447  
     /**
 448  
      * Determines if the expression is valid or not.  This method will validate a single expression or
 449  
      * expressions embedded in a string.  the expression must be well formed i.e. #[bean:user]
 450  
      *
 451  
      * @param expression the expression to validate
 452  
      * @return true if the expression evaluator is recognised
 453  
      */
 454  
     public boolean isValidExpression(String expression)
 455  
     {
 456  
         try
 457  
         {
 458  0
             validateExpression(expression);
 459  0
             return true;
 460  
         }
 461  0
         catch (InvalidExpressionException e)
 462  
         {
 463  0
             logger.warn(e.getMessage());
 464  0
             return false;
 465  
         }
 466  
     }
 467  
 
 468  
     public void validateExpression(String expression) throws InvalidExpressionException
 469  
     {
 470  0
         if (!muleContext.getConfiguration().isValidateExpressions())
 471  
         {
 472  0
             if (logger.isDebugEnabled()) {
 473  0
                 logger.debug("Validate expressions is turned off, no checking done for: " + expression);
 474  
             }
 475  0
             return;
 476  
         }
 477  
         try
 478  
         {
 479  0
             parser.validate(expression);
 480  
         }
 481  0
         catch (IllegalArgumentException e)
 482  
         {
 483  0
             throw new InvalidExpressionException(expression, e.getMessage());
 484  0
         }
 485  
 
 486  0
         final AtomicBoolean valid = new AtomicBoolean(true);
 487  0
         final AtomicBoolean match = new AtomicBoolean(false);
 488  0
         final StringBuffer message = new StringBuffer();
 489  0
         parser.parse(new TemplateParser.TemplateCallback()
 490  0
         {
 491  
             public Object match(String token)
 492  
             {
 493  0
                 match.set(true);
 494  0
                 if (token.indexOf(":") == -1)
 495  
                 {
 496  0
                     if (valid.get())
 497  
                     {
 498  0
                         valid.compareAndSet(true, false);
 499  
                     }
 500  0
                     message.append(token).append(" is invalid\n");
 501  
                 }
 502  0
                 return null;
 503  
             }
 504  
         }, expression);
 505  
 
 506  0
         if (message.length() > 0)
 507  
         {
 508  0
             throw new InvalidExpressionException(expression, message.toString());
 509  
         }
 510  0
         else if(!match.get())
 511  
         {
 512  0
             throw new InvalidExpressionException(expression, "Expression string is not an expression.  Use isExpression(String) to validate first");
 513  
         }
 514  0
     }
 515  
 
 516  
 }