001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.geronimo.system.configuration.condition;
018
019 import java.util.HashMap;
020 import java.util.Map;
021 import java.util.Properties;
022
023 import org.apache.commons.jexl.Expression;
024 import org.apache.commons.jexl.ExpressionFactory;
025 import org.apache.commons.jexl.JexlContext;
026 import org.apache.commons.jexl.JexlHelper;
027 import org.apache.commons.logging.Log;
028 import org.apache.commons.logging.LogFactory;
029
030 /**
031 * Provides a simple facility to evaluate condition expressions using the
032 * <a href="http://jakarta.apache.org/commons/jexl">Jexl</a> language.
033 *
034 * <p>
035 * This class is thread-safe.
036 * </p>
037 *
038 * @version $Rev: 514355 $ $Date: 2007-03-03 23:29:59 -0500 (Sat, 03 Mar 2007) $
039 */
040 public class JexlConditionParser
041 implements ConditionParser
042 {
043 private static final Log log = LogFactory.getLog(JexlConditionParser.class);
044
045 private final Map<String, Object> vars;
046
047 public JexlConditionParser() {
048 // Setup the default vars
049 vars = new HashMap<String, Object>();
050
051 vars.put("java", new JavaVariable());
052 vars.put("os", new OsVariable());
053
054 // Install properties (to allow getProperty(x,y) to be used for defaults
055 Properties props = new Properties();
056 props.putAll(System.getProperties());
057 vars.put("props", props);
058 }
059
060 /**
061 * Evaluate a condition expression.
062 *
063 * @param expression The condition expression to evaluate; must not be null
064 * @return True if the condition is satisfied
065 *
066 * @throws org.apache.geronimo.system.configuration.condition.ConditionParserException Failed to evaluate condition expression
067 */
068 public boolean evaluate(final String expression) throws ConditionParserException {
069 if (expression == null) {
070 throw new IllegalArgumentException("Expression must not be null");
071 }
072
073 // Empty expressions are true
074 if (expression.trim().length() == 0) {
075 log.debug("Expression is empty; skipping evaluation");
076
077 return true;
078 }
079
080 Object result;
081 try {
082 result = doEvaluate(expression);
083 }
084 catch (Exception e) {
085 throw new ConditionParserException("Failed to evaluate expression: " + expression, e);
086 }
087
088 if (result instanceof Boolean) {
089 return (Boolean) result;
090 }
091 else {
092 throw new ConditionParserException("Expression '" + expression + "' did not evaluate to a boolean value; found: " + result);
093 }
094 }
095
096 private Object doEvaluate(final String expression) throws Exception {
097 assert expression != null;
098
099 boolean debug = log.isDebugEnabled();
100
101 if (debug) {
102 log.debug("Evaluating expression: " + expression);
103 }
104
105 Expression expr = ExpressionFactory.createExpression(expression);
106
107 JexlContext ctx = JexlHelper.createContext();
108 ctx.setVars(vars);
109
110 Object result = expr.evaluate(ctx);
111 if (debug) {
112 log.debug("Result: " + result);
113 }
114
115 return result;
116 }
117 }