1 /* 2 * $Id: ExpressionEvaluatorManager.java 12100 2008-06-19 08:58:48Z rossmason $ 3 * -------------------------------------------------------------------------------------- 4 * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.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.util.expression; 11 12 import org.mule.api.lifecycle.Disposable; 13 import org.mule.config.i18n.CoreMessages; 14 import org.mule.util.TemplateParser; 15 16 import java.util.Iterator; 17 18 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap; 19 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentMap; 20 21 /** 22 * Provides universal access for evaluating expressions embedded in Mule configurations, such as Xml, Java, 23 * scripting and annotations. 24 * 25 * Users can register or unregister {@link ExpressionEvaluator} through this interface. 26 * */ 27 public class ExpressionEvaluatorManager 28 { 29 30 public static final String DEFAULT_EXPRESSION_PREFIX = "${"; 31 32 private static TemplateParser parser = TemplateParser.createAntStyleParser(); 33 34 private static ConcurrentMap evaluators = new ConcurrentHashMap(8); 35 36 public static void registerEvaluator(ExpressionEvaluator extractor) 37 { 38 if (extractor == null) 39 { 40 throw new IllegalArgumentException(CoreMessages.objectIsNull("extractor").getMessage()); 41 } 42 Object previous = evaluators.putIfAbsent(extractor.getName(), extractor); 43 if (previous != null) 44 { 45 throw new IllegalArgumentException(CoreMessages.objectAlreadyExists(extractor.getName()).getMessage()); 46 } 47 } 48 49 /** 50 * Checks whether an evaluator is registered with the manager 51 * @param name the name of the expression evaluator 52 * @return true if the evaluator is registered with the manager, false otherwise 53 */ 54 public static boolean isEvaluatorRegistered(String name) 55 { 56 return evaluators.containsKey(name); 57 } 58 59 /** 60 * Removes the evaluator with the given name 61 * @param name the name of the evaluator to remove 62 */ 63 public static ExpressionEvaluator unregisterEvaluator(String name) 64 { 65 if (name==null) 66 { 67 return null; 68 } 69 70 ExpressionEvaluator evaluator = (ExpressionEvaluator) ExpressionEvaluatorManager.evaluators.remove(name); 71 if (evaluator instanceof Disposable) 72 { 73 ((Disposable) evaluator).dispose(); 74 } 75 return evaluator; 76 } 77 78 /** 79 * Evaluates the given expression. The expression should be a single expression definition with or without 80 * enclosing braces. i.e. "mule:serviceName" and "${mule:serviceName}" are both valid. For situations where 81 * one or more expressions need to be parsed within a single text, the {@link #parse(String, Object, boolean)} 82 * method should be used since it will iterate through all expressions in a string. 83 * 84 * @param expression a single expression i.e. xpath://foo 85 * @param object The object (usually {@link org.mule.api.MuleMessage}) to evaluate the expression on. 86 * @return the result of the evaluation 87 * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and 88 * 'failIfNull is set to true. 89 */ 90 public static Object evaluate(String expression, Object object) throws ExpressionRuntimeException 91 { 92 return evaluate(expression, object, DEFAULT_EXPRESSION_PREFIX, false); 93 } 94 95 /** 96 * Evaluates the given expression. The expression should be a single expression definition with or without 97 * enclosing braces. i.e. "mule:serviceName" and "${mule:serviceName}" are both valid. For situations where 98 * one or more expressions need to be parsed within a single text, the {@link #parse(String, Object, boolean)} 99 * method should be used since it will iterate through all expressions in a string. 100 * 101 * @param expression a single expression i.e. xpath://foo 102 * @param object The object (usually {@link org.mule.api.MuleMessage}) to evaluate the expression on. 103 * @param failIfNull determines if an exception should be thrown if expression could not be evaluated or returns 104 * null. 105 * @return the result of the evaluation 106 * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and 107 * 'failIfNull is set to true. 108 */ 109 public static Object evaluate(String expression, Object object, boolean failIfNull) throws ExpressionRuntimeException 110 { 111 return evaluate(expression, object, DEFAULT_EXPRESSION_PREFIX, failIfNull); 112 } 113 114 /** 115 * Evaluates the given expression. The expression should be a single expression definition with or without 116 * enclosing braces. i.e. "mule:serviceName" and "${mule:serviceName}" are both valid. For situations where 117 * one or more expressions need to be parsed within a single text, the {@link #parse(String, Object, boolean)} 118 * method should be used since it will iterate through all expressions in a string. 119 * 120 * @param expression a single expression i.e. xpath://foo 121 * @param evaluator the evaluator to use when executing the expression 122 * @param object The object (usually {@link org.mule.api.MuleMessage}) to evaluate the expression on. 123 * It is unlikely that users will want to change this execpt maybe to use "[" instead. 124 * @param failIfNull determines if an exception should be thrown if expression could not be evaluated or returns 125 * null. 126 * @return the result of the evaluation 127 * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and 128 * 'failIfNull is set to true. 129 */ 130 public static Object evaluate(String expression, String evaluator, Object object, boolean failIfNull) throws ExpressionRuntimeException 131 { 132 ExpressionEvaluator extractor = (ExpressionEvaluator) evaluators.get(evaluator); 133 if (extractor == null) 134 { 135 throw new IllegalArgumentException(CoreMessages.expressionEvaluatorNotRegistered(evaluator).getMessage()); 136 } 137 Object result = extractor.evaluate(expression, object); 138 if (result == null && failIfNull) 139 { 140 throw new ExpressionRuntimeException(CoreMessages.expressionEvaluatorReturnedNull(evaluator, expression)); 141 } 142 return result; 143 } 144 /** 145 * Evaluates the given expression. The expression should be a single expression definition with or without 146 * enclosing braces. i.e. "mule:serviceName" and "${mule:serviceName}" are both valid. For situations where 147 * one or more expressions need to be parsed within a single text, the {@link #parse(String, Object, boolean)} 148 * method should be used since it will iterate through all expressions in a string. 149 * 150 * @param expression a single expression i.e. xpath://foo 151 * @param object The object (usually {@link org.mule.api.MuleMessage}) to evaluate the expression on. 152 * @param expressionPrefix the expression prefix to use. The default is "${" but any character is valid. 153 * It is unlikely that users will want to change this except maybe to use "[" instead. 154 * @param failIfNull determines if an exception should be thrown if expression could not be evaluated or returns 155 * null. 156 * @return the result of the evaluation 157 * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and 158 * 'failIfNull is set to true. 159 */ 160 public static Object evaluate(String expression, Object object, String expressionPrefix, boolean failIfNull) throws ExpressionRuntimeException 161 { 162 String name; 163 164 if (expression == null) 165 { 166 throw new IllegalArgumentException(CoreMessages.objectIsNull("expression").getMessage()); 167 } 168 if (expression.startsWith(expressionPrefix)) 169 { 170 expression = expression.substring(2, expression.length()-1); 171 } 172 int i = expression.indexOf(":"); 173 if (i >- 1) 174 { 175 name = expression.substring(0, i); 176 expression = expression.substring(i+1); 177 } 178 else 179 { 180 name = expression; 181 expression = null; 182 } 183 return evaluate(expression, name, object, failIfNull); 184 185 186 } 187 188 /** 189 * Evaluates expressions in a given string. This method will iterate through each expression and evaluate it. If 190 * a user needs to evaluate a single expression they can use {@link #evaluate(String, Object, boolean)}. 191 * 192 * @param expression a single expression i.e. xpath://foo 193 * @param object The object (usually {@link org.mule.api.MuleMessage}) to evaluate the expression on. 194 195 * @return the result of the evaluation 196 * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and 197 * 'failIfNull is set to true. 198 */ 199 public static String parse(String expression, Object object) throws ExpressionRuntimeException 200 { 201 return parse(expression, object, false); 202 } 203 204 /** 205 * Evaluates expressions in a given string. This method will iterate through each expression and evaluate it. If 206 * a user needs to evaluate a single expression they can use {@link #evaluate(String, Object, boolean)}. 207 * 208 * @param expression a single expression i.e. xpath://foo 209 * @param object The object (usually {@link org.mule.api.MuleMessage}) to evaluate the expression on. 210 * @param failIfNull determines if an exception should be thrown if expression could not be evaluated or returns 211 * null. 212 * @return the result of the evaluation 213 * @throws ExpressionRuntimeException if the expression is invalid, or a null is found for the expression and 214 * 'failIfNull is set to true. 215 */ 216 public static String parse(final String expression, final Object object, final boolean failIfNull) throws ExpressionRuntimeException 217 { 218 return parser.parse(new TemplateParser.TemplateCallback() { 219 public Object match(String token) 220 { 221 return evaluate(token, object, failIfNull); 222 } 223 }, expression); 224 } 225 226 /** 227 * Clears all registered evaluators from the manager. 228 */ 229 public static synchronized void clearEvaluators() 230 { 231 for (Iterator iterator = evaluators.values().iterator(); iterator.hasNext();) 232 { 233 ExpressionEvaluator evaluator = (ExpressionEvaluator)iterator.next(); 234 if(evaluator instanceof Disposable) 235 { 236 ((Disposable) evaluator).dispose(); 237 } 238 } 239 evaluators.clear(); 240 } 241 242 /** 243 * Determines if the expression is valid or not. This only validates single expressions. 244 * @param expression the expression to validate 245 * @return true if the expression evaluator is recognised 246 */ 247 public static boolean isValidExpression(String expression) 248 { 249 return isValidExpression(expression, DEFAULT_EXPRESSION_PREFIX); 250 } 251 252 /** 253 * Determines if the expression is valid or not. This only validates single expressions. 254 * @param expression the expression to validate 255 * @param expressionPrefix the prefix used for this expression. if the expression is ${bean:msg.header} 256 * the prefix is "${" 257 * @return true if the expression evaluator is recognised 258 */ 259 public static boolean isValidExpression(String expression, String expressionPrefix) 260 { 261 if(expression.startsWith(expressionPrefix)) 262 { 263 expression = expression.substring(2, expression.length()-1); 264 } 265 String name; 266 int i = expression.indexOf(":"); 267 if(i>-1) 268 { 269 name = expression.substring(0, i); 270 } 271 else 272 { 273 name = expression; 274 } 275 return isEvaluatorRegistered(name); 276 } 277 278 }