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 */ 017package org.apache.activemq.filter; 018 019import java.util.HashMap; 020import java.util.List; 021import org.apache.activemq.filter.function.FilterFunction; 022 023/** 024 * Function call expression for use in selector expressions. Includes an extensible interface to allow custom 025 * functions to be added without changes to the core. 026 * <p/> 027 * Use registerFunction() to register new function implementations for use in selectors. 028 */ 029 030public class FunctionCallExpression implements Expression { 031 protected static final HashMap<String, functionRegistration> functionRegistry = new HashMap(); 032 033 protected String functionName; 034 protected java.util.ArrayList arguments; 035 protected FilterFunction filterFunc; 036 037 static { 038 // Register the built-in functions. It would be nice to just have each function class register 039 // itself, but that only works when the classes are loaded, which may be never. 040 041 org.apache.activemq.filter.function.BuiltinFunctionRegistry.register(); 042 } 043 044 045 /** 046 * Register the function with the specified name. 047 * 048 * @param name - the function name, as used in selector expressions. Case Sensitive. 049 * @param impl - class which implements the function interface, including parse-time and evaluation-time 050 * operations. 051 * @return true - if the function is successfully registered; false - if a function with the same name is 052 * already registered. 053 */ 054 055 public static boolean registerFunction(String name, FilterFunction impl) { 056 boolean result; 057 058 result = true; 059 060 synchronized (functionRegistry) { 061 if (functionRegistry.containsKey(name)) 062 result = false; 063 else 064 functionRegistry.put(name, new functionRegistration(impl)); 065 } 066 067 return result; 068 } 069 070 /** 071 * Remove the registration of the function with the specified name. 072 * <p/> 073 * Note that parsed expressions using this function will still access its implementation after this call. 074 * 075 * @param name - name of the function to remove. 076 */ 077 078 public static void deregisterFunction(String name) { 079 synchronized (functionRegistry) { 080 functionRegistry.remove(name); 081 } 082 } 083 084 085 /** 086 * Constructs a function call expression with the named function and argument list. 087 * <p/> 088 * Use createFunctionCall() to create instances. 089 * 090 * @exception invalidFunctionExpressionException - if the function name is not valid. 091 */ 092 093 protected FunctionCallExpression(String func_name, List<Expression> args) 094 throws invalidFunctionExpressionException { 095 functionRegistration func_reg; 096 097 synchronized (functionRegistry) { 098 func_reg = functionRegistry.get(func_name); 099 } 100 101 if (func_reg != null) { 102 this.arguments = new java.util.ArrayList(); 103 this.arguments.addAll(args); 104 this.functionName = func_name; 105 this.filterFunc = func_reg.getFilterFunction(); 106 } else { 107 throw new invalidFunctionExpressionException("invalid function name, \"" + func_name + "\""); 108 } 109 } 110 111 112 /** 113 * Create a function call expression for the named function and argument list, returning a Boolean function 114 * call expression if the function returns a boolean value so that it may be used in boolean contexts. 115 * Used by the parser when a function call is identified. Note that the function call is created after all 116 * argument expressions so that the function call can properly detect whether it evaluates to a Boolean value. 117 * 118 * @param func_name - name of the function, as used in selectors. 119 * @param args - list of argument expressions passed to the function. 120 * @return an instance of a BooleanFunctionCallExpr if the function returns a boolean value in this call, 121 * or a FunctionCallExpression otherwise. 122 * @exception invalidFunctionExpression - if the function name is not valid, or the given argument list is 123 * not valid for the function. 124 */ 125 126 public static FunctionCallExpression createFunctionCall(String func_name, List<Expression> args) 127 throws invalidFunctionExpressionException { 128 FunctionCallExpression result; 129 130 // 131 // Create a function call expression by default to use with validating the function call 132 // expression and checking whether it returns a boolean result. 133 // 134 135 result = new FunctionCallExpression(func_name, args); 136 137 138 // 139 // Check wether the function accepts this expression. I.E. are the arguments valid? 140 // 141 142 if (result.filterFunc.isValid(result)) { 143 // 144 // If the result of the call is known to alwyas return a boolean value, wrap this 145 // expression as a valid BooleanExpression so it will be accepted as a boolean result 146 // by the selector grammar. 147 // 148 149 if (result.filterFunc.returnsBoolean(result)) 150 result = new BooleanFunctionCallExpr(func_name, args); 151 } else { 152 // 153 // Function does not like this expression. 154 // 155 156 throw new invalidFunctionExpressionException("invalid call of function " + func_name); 157 } 158 159 return result; 160 } 161 162 163 /** 164 * Retrieve the number of arguments for the function call defined in this expression. 165 * 166 * @return the number of arguments being passed to the function. 167 */ 168 169 public int getNumArguments() { 170 return arguments.size(); 171 } 172 173 174 /** 175 * Retrieve the argument at the specified index; the first argument is index 0. Used by implementations of 176 * FilterFunction objects to check arguments and evaluate them, as needed. 177 * 178 * @param which - number of the argument to retrieve; the first is 0. 179 */ 180 181 public Expression getArgument(int which) { 182 return (Expression) arguments.get(which); 183 } 184 185 186 /** 187 * Evaluate the function call expression in the context given. 188 * 189 * @see Expression#evaluate 190 */ 191 192 public Object evaluate(MessageEvaluationContext message_ctx) 193 throws javax.jms.JMSException { 194 return this.filterFunc.evaluate(this, message_ctx); 195 } 196 197 198 /** 199 * Translate the expression back into text in a form similar to the input to the selector parser. 200 */ 201 202 @Override 203 public String toString() { 204 StringBuilder result; 205 boolean first_f; 206 207 result = new StringBuilder(); 208 209 result.append(functionName); 210 result.append("("); 211 first_f = true; 212 213 for (Object arg : arguments) { 214 if (first_f) 215 first_f = false; 216 else 217 result.append(", "); 218 219 result.append(arg.toString()); 220 } 221 222 result.append(")"); 223 224 return result.toString(); 225 } 226 227 228 //// //// 229 //// FUNCTION REGISTRATION //// 230 //// //// 231 232 /** 233 * Maintain a single function registration. 234 */ 235 236 protected static class functionRegistration { 237 protected FilterFunction filterFunction; 238 239 /** 240 * Constructs a function registration for the given function implementation. 241 */ 242 243 public functionRegistration(FilterFunction func) { 244 this.filterFunction = func; 245 } 246 247 248 /** 249 * Retrieve the filter function implementation. 250 */ 251 252 public FilterFunction getFilterFunction() { 253 return filterFunction; 254 } 255 256 257 /** 258 * Set the filter function implementation for this registration. 259 */ 260 261 public void setFilterFunction(FilterFunction func) { 262 filterFunction = func; 263 } 264 } 265 266 267 /** 268 * Exception indicating that an invalid function call expression was created, usually by the selector parser. 269 * Conditions include invalid function names and invalid function arguments. 270 */ 271 272 public static class invalidFunctionExpressionException extends java.lang.Exception { 273 public invalidFunctionExpressionException(String msg) { 274 super(msg); 275 } 276 277 public invalidFunctionExpressionException(String msg, java.lang.Throwable cause) { 278 super(msg, cause); 279 } 280 } 281}