https://issues.apache.org/jira/browse/AMQ-3097 - apply patch with some additional unit test, with thanks

git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@1478973 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Gary Tully 2013-05-03 20:43:59 +00:00
parent 3a8eb74a9f
commit bf071376b5
13 changed files with 1057 additions and 1 deletions

View File

@ -56,6 +56,7 @@ import java.util.*;
import javax.jms.InvalidSelectorException;
import org.apache.activemq.filter.*;
import org.apache.activemq.filter.FunctionCallExpression.invalidFunctionExpressionException;
import org.apache.activemq.util.LRUCache;
/**
@ -130,7 +131,6 @@ public class SelectorParser {
throw new ParseException("Expression will not result in a boolean value: " + value);
}
}
PARSER_END(SelectorParser)
@ -490,6 +490,9 @@ Expression unaryExpr() :
left = UnaryExpression.createXQuery( s );
}
|
LOOKAHEAD( <ID> "(" )
left = functionCallExpr()
|
left = primaryExpr()
)
{
@ -498,6 +501,42 @@ Expression unaryExpr() :
}
Expression functionCallExpr () :
{
Token func_name;
FunctionCallExpression func_call = null;
Expression arg = null;
ArrayList arg_list = new ArrayList();
}
{
func_name = <ID> "("
(
arg = unaryExpr()
{
arg_list.add(arg);
}
(
","
arg = unaryExpr()
{
arg_list.add(arg);
}
) *
)
")"
{
try
{
return FunctionCallExpression.createFunctionCall(func_name.image, arg_list);
}
catch ( invalidFunctionExpressionException inv_exc )
{
// Re-throw as an error to avoid the need to propogate the throws declaration.
throw new Error("invalid function call expression", inv_exc);
}
}
}
Expression primaryExpr() :
{
Expression left=null;

View File

@ -0,0 +1,66 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.filter;
import java.util.List;
/**
* Function call expression that evaluates to a boolean value. Selector parsing requires BooleanExpression objects for
* Boolean expressions, such as operands to AND, and as the final result of a selector. This provides that interface
* for function call expressions that resolve to Boolean values.
* <p/>
* If a function can return different types at evaluation-time, the function implementation needs to decide whether it
* supports casting to Boolean at parse-time.
*
* @see FunctionCallExpression#createFunctionCall
*/
public class BooleanFunctionCallExpr extends FunctionCallExpression implements BooleanExpression {
/**
* Constructs a function call expression with the named filter function and arguments, which returns a boolean
* result.
*
* @param func_name - Name of the filter function to be called when evaluated.
* @param args - List of argument expressions passed to the function.
*/
public BooleanFunctionCallExpr(String func_name, List<Expression> args)
throws invalidFunctionExpressionException {
super(func_name, args);
}
/**
* Evaluate the function call expression, in the given context, and return an indication of whether the
* expression "matches" (i.e.&nbsp;evaluates to true).
*
* @param message_ctx - message context against which the expression will be evaluated.
* @return the boolean evaluation of the function call expression.
*/
public boolean matches(MessageEvaluationContext message_ctx) throws javax.jms.JMSException {
Boolean result;
result = (Boolean) evaluate(message_ctx);
if (result != null)
return result.booleanValue();
return false;
}
}

View File

@ -0,0 +1,281 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.filter;
import java.util.HashMap;
import java.util.List;
import org.apache.activemq.filter.function.FilterFunction;
/**
* Function call expression for use in selector expressions. Includes an extensible interface to allow custom
* functions to be added without changes to the core.
* <p/>
* Use registerFunction() to register new function implementations for use in selectors.
*/
public class FunctionCallExpression implements Expression {
protected static final HashMap<String, functionRegistration> functionRegistry = new HashMap();
protected String functionName;
protected java.util.ArrayList arguments;
protected FilterFunction filterFunc;
static {
// Register the built-in functions. It would be nice to just have each function class register
// itself, but that only works when the classes are loaded, which may be never.
org.apache.activemq.filter.function.BuiltinFunctionRegistry.register();
}
/**
* Register the function with the specified name.
*
* @param name - the function name, as used in selector expressions. Case Sensitive.
* @param impl - class which implements the function interface, including parse-time and evaluation-time
* operations.
* @return true - if the function is successfully registered; false - if a function with the same name is
* already registered.
*/
public static boolean registerFunction(String name, FilterFunction impl) {
boolean result;
result = true;
synchronized (functionRegistry) {
if (functionRegistry.containsKey(name))
result = false;
else
functionRegistry.put(name, new functionRegistration(impl));
}
return result;
}
/**
* Remove the registration of the function with the specified name.
* <p/>
* Note that parsed expressions using this function will still access its implementation after this call.
*
* @param name - name of the function to remove.
*/
public static void deregisterFunction(String name) {
synchronized (functionRegistry) {
functionRegistry.remove(name);
}
}
/**
* Constructs a function call expression with the named function and argument list.
* <p/>
* Use createFunctionCall() to create instances.
*
* @exception invalidFunctionExpressionException - if the function name is not valid.
*/
protected FunctionCallExpression(String func_name, List<Expression> args)
throws invalidFunctionExpressionException {
functionRegistration func_reg;
synchronized (functionRegistry) {
func_reg = functionRegistry.get(func_name);
}
if (func_reg != null) {
this.arguments = new java.util.ArrayList();
this.arguments.addAll(args);
this.functionName = func_name;
this.filterFunc = func_reg.getFilterFunction();
} else {
throw new invalidFunctionExpressionException("invalid function name, \"" + func_name + "\"");
}
}
/**
* Create a function call expression for the named function and argument list, returning a Boolean function
* call expression if the function returns a boolean value so that it may be used in boolean contexts.
* Used by the parser when a function call is identified. Note that the function call is created after all
* argument expressions so that the function call can properly detect whether it evaluates to a Boolean value.
*
* @param func_name - name of the function, as used in selectors.
* @param args - list of argument expressions passed to the function.
* @return an instance of a BooleanFunctionCallExpr if the function returns a boolean value in this call,
* or a FunctionCallExpression otherwise.
* @exception invalidFunctionExpression - if the function name is not valid, or the given argument list is
* not valid for the function.
*/
public static FunctionCallExpression createFunctionCall(String func_name, List<Expression> args)
throws invalidFunctionExpressionException {
FunctionCallExpression result;
//
// Create a function call expression by default to use with validating the function call
// expression and checking whether it returns a boolean result.
//
result = new FunctionCallExpression(func_name, args);
//
// Check wether the function accepts this expression. I.E. are the arguments valid?
//
if (result.filterFunc.isValid(result)) {
//
// If the result of the call is known to alwyas return a boolean value, wrap this
// expression as a valid BooleanExpression so it will be accepted as a boolean result
// by the selector grammar.
//
if (result.filterFunc.returnsBoolean(result))
result = new BooleanFunctionCallExpr(func_name, args);
} else {
//
// Function does not like this expression.
//
throw new invalidFunctionExpressionException("invalid call of function " + func_name);
}
return result;
}
/**
* Retrieve the number of arguments for the function call defined in this expression.
*
* @return the number of arguments being passed to the function.
*/
public int getNumArguments() {
return arguments.size();
}
/**
* Retrieve the argument at the specified index; the first argument is index 0. Used by implementations of
* FilterFunction objects to check arguments and evaluate them, as needed.
*
* @param which - number of the argument to retrieve; the first is 0.
*/
public Expression getArgument(int which) {
return (Expression) arguments.get(which);
}
/**
* Evaluate the function call expression in the context given.
*
* @see Expression#evaluate
*/
public Object evaluate(MessageEvaluationContext message_ctx)
throws javax.jms.JMSException {
return this.filterFunc.evaluate(this, message_ctx);
}
/**
* Translate the expression back into text in a form similar to the input to the selector parser.
*/
@Override
public String toString() {
StringBuilder result;
boolean first_f;
result = new StringBuilder();
result.append(functionName);
result.append("(");
first_f = true;
for (Object arg : arguments) {
if (first_f)
first_f = false;
else
result.append(", ");
result.append(arg.toString());
}
result.append(")");
return result.toString();
}
//// ////
//// FUNCTION REGISTRATION ////
//// ////
/**
* Maintain a single function registration.
*/
protected static class functionRegistration {
protected FilterFunction filterFunction;
/**
* Constructs a function registration for the given function implementation.
*/
public functionRegistration(FilterFunction func) {
this.filterFunction = func;
}
/**
* Retrieve the filter function implementation.
*/
public FilterFunction getFilterFunction() {
return filterFunction;
}
/**
* Set the filter function implementation for this registration.
*/
public void setFilterFunction(FilterFunction func) {
filterFunction = func;
}
}
/**
* Exception indicating that an invalid function call expression was created, usually by the selector parser.
* Conditions include invalid function names and invalid function arguments.
*/
public static class invalidFunctionExpressionException extends java.lang.Exception {
public invalidFunctionExpressionException(String msg) {
super(msg);
}
public invalidFunctionExpressionException(String msg, java.lang.Throwable cause) {
super(msg, cause);
}
}
}

View File

@ -0,0 +1,37 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.filter.function;
import org.apache.activemq.filter.FunctionCallExpression;
/**
* Registry of built-in functions. Add built-in functions to this list to make sure they are registered at startup.
* <p/>
* Custom add-ons that are not built-in to the core ActiveMQ should not be listed here.
* Use FunctionCallExpression.registerFunction() directly.
*/
public class BuiltinFunctionRegistry {
public static void register() {
FunctionCallExpression.registerFunction("INLIST", new inListFunction());
FunctionCallExpression.registerFunction("MAKELIST", new makeListFunction());
FunctionCallExpression.registerFunction("REGEX", new regexMatchFunction());
FunctionCallExpression.registerFunction("REPLACE", new replaceFunction());
FunctionCallExpression.registerFunction("SPLIT", new splitFunction());
}
}

View File

@ -0,0 +1,61 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.filter.function;
import org.apache.activemq.filter.FunctionCallExpression;
import org.apache.activemq.filter.MessageEvaluationContext;
/**
* Interface required for objects that will be registered as functions for use in selectors. Handles parse-
* time and evaluation-time operations.
*/
public interface FilterFunction {
/**
* Check whether the function, as it is used, is valid. Checking arguments here will return errors
* to clients at the time invalid selectors are initially specified, rather than waiting until the selector is
* applied to a message.
*
* @param FunctionCallExpression expr - the full expression of the function call, as used.
* @return true - if the function call is valid; false - otherwise.
*/
public boolean isValid(FunctionCallExpression expr);
/**
* Determine whether the function, as it will be called, returns a boolean value. Called during
* expression parsing after the full expression for the function call, including its arguments, has
* been parsed. This allows functions with variable return types to function as boolean expressions in
* selectors without sacrificing parse-time checking.
*
* @param FunctionCallExpression expr - the full expression of the function call, as used.
* @return true - if the function returns a boolean value for its use in the given expression;
* false - otherwise.
*/
public boolean returnsBoolean(FunctionCallExpression expr);
/**
* Evaluate the function call in the given context. The arguments must be evaluated, as-needed, by the
* function. Note that boolean expressions must return Boolean objects.
*
* @param FunctionCallExpression expr - the full expression of the function call, as used.
* @param MessageEvaluationContext message - the context within which to evaluate the call.
*/
public Object evaluate(FunctionCallExpression expr, MessageEvaluationContext message)
throws javax.jms.JMSException;
}

View File

@ -0,0 +1,93 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.filter.function;
import org.apache.activemq.filter.FunctionCallExpression;
import org.apache.activemq.filter.MessageEvaluationContext;
/**
* Filter function that matches a value against a list of values and evaluates to an indicator of membership in the
* list. For example:
* <p/>
* <p style="margin-left: 4em">
* INLIST( SPLIT('1,2,3', ',') , '2' )
* </p>
* <p/>
* Note that the first argument must be a List. Strings containing lists are not acceptable; for example,
* INLIST('1,2,3', '1'), will cause an exception to be thrown at evaluation-time.
*/
public class inListFunction implements FilterFunction {
/**
* Check whether the given expression is a valid call of this function. Two arguments are required. Note that
* the evaluated results of the arguments will be compared with Object#equals().
*
* @param expr - the expression consisting of a call to this function.
* @return true - if the expression is valid; false - otherwise.
*/
public boolean isValid(FunctionCallExpression expr) {
if (expr.getNumArguments() != 2)
return false;
return true;
}
/**
* Check whether the given expression, which consists of a call to this function, evaluates to a Boolean.
* If the function can return different more than one type of value at evaluation-time, it must decide whether
* to cast the result to a Boolean at this time.
*
* @param expr - the expression consisting of a call to this function.
* @return true - if the expression is valid; false - otherwise.
*/
public boolean returnsBoolean(FunctionCallExpression expr) {
return true;
}
/**
* Evalutate the given expression, which consists of a call to this function, in the context given. Checks
* whether the second argument is a member of the list in the first argument.
*
* @param expr - the expression consisting of a call to this function.
* @param message_ctx - the context in which the call is being evaluated.
* @return Boolean - the result of the evaluation.
*/
public Object evaluate(FunctionCallExpression expr, MessageEvaluationContext message_ctx)
throws javax.jms.JMSException {
java.util.List arr;
int cur;
Object cand;
boolean found_f;
arr = (java.util.List) expr.getArgument(0).evaluate(message_ctx);
cand = expr.getArgument(1).evaluate(message_ctx);
cur = 0;
found_f = false;
while ((cur < arr.size()) && (!found_f)) {
found_f = arr.get(cur).equals(cand);
cur++;
}
return Boolean.valueOf(found_f);
}
}

View File

@ -0,0 +1,82 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.filter.function;
import org.apache.activemq.filter.FunctionCallExpression;
import org.apache.activemq.filter.MessageEvaluationContext;
/**
* Filter function that creates a list with each argument being one element in the list.
* For example:
* <p/>
* <p style="margin-left: 4em">
* MAKELIST( '1', '2', '3' )
* </p>
*/
public class makeListFunction implements FilterFunction {
/**
* Check whether the given expression is a valid call of this function. Any number of arguments is accepted.
*
* @param expr - the expression consisting of a call to this function.
* @return true - if the expression is valid; false - otherwise.
*/
public boolean isValid(FunctionCallExpression expr) {
return true;
}
/**
* Indicate that this function never evaluates to a Boolean result.
*
* @param expr - the expression consisting of a call to this function.
* @return false - this Filter Function never evaluates to a Boolean.
*/
public boolean returnsBoolean(FunctionCallExpression expr) {
return false;
}
/**
* Evalutate the given expression, which consists of a call to this function, in the context given. Creates
* a list containing the evaluated results of its argument expressions.
*
* @param expr - the expression consisting of a call to this function.
* @param message_ctx - the context in which the call is being evaluated.
* @return java.util.List - the result of the evaluation.
*/
public Object evaluate(FunctionCallExpression expr, MessageEvaluationContext message)
throws javax.jms.JMSException {
java.util.ArrayList ele_arr;
int num_arg;
int cur;
num_arg = expr.getNumArguments();
ele_arr = new java.util.ArrayList(num_arg);
cur = 0;
while (cur < num_arg) {
ele_arr.add(expr.getArgument(cur).evaluate(message));
cur++;
}
return (java.util.List) ele_arr;
}
}

View File

@ -0,0 +1,27 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
</head>
<body>
<p>
Filter Function implementations for JMS Selectors.
</p>
</body>
</html>

View File

@ -0,0 +1,166 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.filter.function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.activemq.filter.FunctionCallExpression;
import org.apache.activemq.filter.MessageEvaluationContext;
import org.apache.activemq.util.LRUCache;
/**
* Filter function that matches a value against a regular expression.
* <p/>
* <p style="margin-left: 4em">
* REGEX( 'A.B', 'A-B' )
* </p>
* <p/>
* Note that the regular expression is not anchored; use the anchor characters, ^ and $, as-needed. For example,
* REGEX( 'AA', 'XAAX' ) evaluates to true while REGEX( '^AA$' , 'XAAX' ) evaluates to false.
*/
public class regexMatchFunction implements FilterFunction {
protected static final LRUCache<String, Pattern> compiledExprCache = new LRUCache(100);
/**
* Check whether the given expression is a valid call of this function. Two arguments are required. When
* evaluated, the arguments are converted to strings if they are not already strings.
*
* @param expr - the expression consisting of a call to this function.
* @return true - if the expression is valid; false - otherwise.
*/
public boolean isValid(FunctionCallExpression expr) {
if (expr.getNumArguments() == 2)
return true;
return false;
}
/**
* Indicate that this Filter Function evaluates to a Boolean result.
*
* @param expr - the expression consisting of a call to this function.
* @return true - this function always evaluates to a Boolean result.
*/
public boolean returnsBoolean(FunctionCallExpression expr) {
return true;
}
/**
* Evalutate the given expression, which consists of a call to this function, in the context given. Returns
* an indication of whether the second argument matches the regular expression in the first argument.
*
* @param expr - the expression consisting of a call to this function.
* @param message_ctx - the context in which the call is being evaluated.
* @return true - if the value matches the regular expression; false - otherwise.
*/
public Object evaluate(FunctionCallExpression expr, MessageEvaluationContext message)
throws javax.jms.JMSException {
Object reg;
Object cand;
String reg_str;
String cand_str;
Pattern pat;
Matcher match_eng;
//
// Evaluate the first argument (the regular expression).
//
reg = expr.getArgument(0).evaluate(message);
if (reg != null) {
// Convert to a string, if it's not already a string.
if (reg instanceof String)
reg_str = (String) reg;
else
reg_str = reg.toString();
//
// Evaluate the second argument (the candidate to match against the regular
// expression).
//
cand = expr.getArgument(1).evaluate(message);
if (cand != null) {
// Convert to a string, if it's not already a string.
if (cand instanceof String)
cand_str = (String) cand;
else
cand_str = cand.toString();
//
// Obtain the compiled regular expression and match it.
//
pat = getCompiledPattern(reg_str);
match_eng = pat.matcher(cand_str);
//
// Return an indication of whether the regular expression matches at any
// point in the candidate (see Matcher#find()).
//
return Boolean.valueOf(match_eng.find());
}
}
return Boolean.FALSE;
}
/**
* Retrieve a compiled pattern for the given pattern string. A cache of recently used strings is maintained to
* improve performance.
*
* @param reg_ex_str - the string specifying the regular expression.
* @return Pattern - compiled form of the regular expression.
*/
protected Pattern getCompiledPattern(String reg_ex_str) {
Pattern result;
//
// Look for the compiled pattern in the cache.
//
synchronized (compiledExprCache) {
result = compiledExprCache.get(reg_ex_str);
}
//
// If it was not found, compile it and add it to the cache.
//
if (result == null) {
result = Pattern.compile(reg_ex_str);
synchronized (compiledExprCache) {
compiledExprCache.put(reg_ex_str, result);
}
}
return result;
}
}

View File

@ -0,0 +1,84 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.filter.function;
import org.apache.activemq.filter.FunctionCallExpression;
import org.apache.activemq.filter.MessageEvaluationContext;
/**
* Function which replaces regular expression matches in a source string to a replacement literal.
* <p/>
* For Example:
* REPLACE('1,2/3', '[,/]', ';') returns '1;2;3'
*/
public class replaceFunction implements FilterFunction {
/**
* Check whether the given expression is valid for this function.
*
* @param expr - the expression consisting of a call to this function.
* @return true - if three arguments are passed to the function; false - otherwise.
*/
public boolean isValid(FunctionCallExpression expr) {
if (expr.getNumArguments() == 3)
return true;
return false;
}
/**
* Indicate that this function does not return a boolean value.
*
* @param expr - the expression consisting of a call to this function.
* @return false - this filter function always evaluates to a string.
*/
public boolean returnsBoolean(FunctionCallExpression expr) {
return false;
}
/**
* Evaluate the given expression for this function in the given context. The result of the evaluation is a
* string with all matches of the regular expression, from the evaluation of the second argument, replaced by
* the string result from the evaluation of the third argument. Replacement is performed by
* String#replaceAll().
* <p/>
* Note that all three arguments must be Strings.
*
* @param expr - the expression consisting of a call to this function.
* @return String - the result of the replacement.
*/
public Object evaluate(FunctionCallExpression expr, MessageEvaluationContext message_ctx)
throws javax.jms.JMSException {
String src;
String match_regex;
String repl_lit;
String result;
src = (String) expr.getArgument(0).evaluate(message_ctx);
match_regex = (String) expr.getArgument(1).evaluate(message_ctx);
repl_lit = (String) expr.getArgument(2).evaluate(message_ctx);
result = src.replaceAll(match_regex, repl_lit);
return result;
}
}

View File

@ -0,0 +1,87 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.filter.function;
import org.apache.activemq.filter.FunctionCallExpression;
import org.apache.activemq.filter.MessageEvaluationContext;
/**
* Function which splits a string into a list of strings given a regular expression for the separator.
*/
public class splitFunction implements FilterFunction {
/**
* Check whether the given expression is valid for this function.
*
* @param expr - the expression consisting of a call to this function.
* @return true - if two or three arguments are passed to the function; false - otherwise.
*/
public boolean isValid(FunctionCallExpression expr) {
if ((expr.getNumArguments() >= 2) && (expr.getNumArguments() <= 3))
return true;
return false;
}
/**
* Indicate that this function does not return a boolean value.
*
* @param expr - the expression consisting of a call to this function.
* @return false - indicating this filter function never evaluates to a boolean result.
*/
public boolean returnsBoolean(FunctionCallExpression expr) {
return false;
}
/**
* Evaluate the given expression for this function in the given context. A list of zero or more strings
* results from the evaluation. The result of the evaluation of the first argument is split with the regular
* expression which results from the evaluation of the second argument. If a third argument is given, it
* is an integer which limits the split. String#split() performs the split.
* <p/>
* The first two arguments must be Strings. If a third is given, it must be an Integer.
*
* @param expr - the expression consisting of a call to this function.
* @return List - a list of Strings resulting from the split.
*/
public Object evaluate(FunctionCallExpression expr, MessageEvaluationContext message_ctx)
throws javax.jms.JMSException {
String src;
String split_pat;
String[] result;
src = (String) expr.getArgument(0).evaluate(message_ctx);
split_pat = (String) expr.getArgument(1).evaluate(message_ctx);
if (expr.getNumArguments() > 2) {
Integer limit;
limit = (Integer) expr.getArgument(2).evaluate(message_ctx);
result = src.split(split_pat, limit.intValue());
} else {
result = src.split(split_pat);
}
return java.util.Arrays.asList(result);
}
}

View File

@ -16,9 +16,11 @@
*/
package org.apache.activemq.selector;
import javax.jms.InvalidSelectorException;
import junit.framework.TestCase;
import org.apache.activemq.filter.BooleanExpression;
import org.apache.activemq.filter.BooleanFunctionCallExpr;
import org.apache.activemq.filter.ComparisonExpression;
import org.apache.activemq.filter.Expression;
import org.apache.activemq.filter.LogicExpression;
@ -33,6 +35,19 @@ import org.slf4j.LoggerFactory;
public class SelectorParserTest extends TestCase {
private static final Logger LOG = LoggerFactory.getLogger(SelectorParserTest.class);
public void testFunctionCall() throws Exception {
Object filter = parse("REGEX('sales.*', group)");
assertTrue("expected type", filter instanceof BooleanFunctionCallExpr);
LOG.info("function exp:" + filter);
// non existent function
try {
parse("DoesNotExist('sales.*', group)");
fail("expect ex on non existent function");
} catch (InvalidSelectorException expected) {}
}
public void testParseXPath() throws Exception {
BooleanExpression filter = parse("XPATH '//title[@lang=''eng'']'");
assertTrue("Created XPath expression", filter instanceof XPathExpression);

View File

@ -329,6 +329,24 @@ public class SelectorTest extends TestCase {
assertInvalidSelector(message, "=TEST 'test'");
}
public void testFunctionSelector() throws Exception {
Message message = createMessage();
assertSelector(message, "REGEX('1870414179', SessionserverId)", false);
message.setLongProperty("SessionserverId", 1870414179);
assertSelector(message, "REGEX('1870414179', SessionserverId)", true);
assertSelector(message, "REGEX('[0-9]*', SessionserverId)", true);
assertSelector(message, "REGEX('^[1-8]*$', SessionserverId)", false);
assertSelector(message, "REGEX('^[1-8]*$', SessionserverId)", false);
assertSelector(message, "INLIST(SPLIT('Tom,Dick,George',','), name)", false);
assertSelector(message, "INLIST(SPLIT('Tom,James,George',','), name)", true);
assertSelector(message, "INLIST(MAKELIST('Tom','Dick','George'), name)", false);
assertSelector(message, "INLIST(MAKELIST('Tom','James','George'), name)", true);
assertSelector(message, "REGEX('connection1111', REPLACE(JMSMessageID,':',''))", true);
}
protected Message createMessage() throws JMSException {
Message message = createMessage("FOO.BAR");
message.setJMSType("selector-test");