You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by on...@apache.org on 2017/06/22 12:10:12 UTC
camel git commit: CAMEL-11420-Add contains ignore case operator to
simple language
Repository: camel
Updated Branches:
refs/heads/master 95ebcb4fe -> d97c96251
CAMEL-11420-Add contains ignore case operator to simple language
CAMEL-11420-add jmh test
CAMEL-11420 - null check added for containsIgnoreCase in StringHelper
CAMEL-11420 - CR fixes
CAMEL-11420- update simple-language.adoc for contains ignore case
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/d97c9625
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/d97c9625
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/d97c9625
Branch: refs/heads/master
Commit: d97c96251a21b2d4b525401136ec30502b5dc79a
Parents: 95ebcb4
Author: onders86 <on...@gmail.com>
Authored: Mon Jun 19 20:06:38 2017 +0300
Committer: onders86 <on...@gmail.com>
Committed: Thu Jun 22 15:07:47 2017 +0300
----------------------------------------------------------------------
.../src/main/resources/camel-checkstyle.xml | 2 +-
camel-core/src/main/docs/simple-language.adoc | 2 +
.../apache/camel/builder/PredicateBuilder.java | 21 +++++
.../camel/language/simple/SimpleTokenizer.java | 1 +
.../language/simple/ast/BinaryExpression.java | 2 +
.../simple/types/BinaryOperatorType.java | 9 ++-
.../org/apache/camel/util/ObjectHelper.java | 37 +++++++++
.../org/apache/camel/util/StringHelper.java | 35 ++++++++
.../language/simple/SimpleOperatorTest.java | 7 ++
.../camel/itest/jmh/ContainsIgnoreCaseTest.java | 85 ++++++++++++++++++++
10 files changed, 199 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/d97c9625/buildingtools/src/main/resources/camel-checkstyle.xml
----------------------------------------------------------------------
diff --git a/buildingtools/src/main/resources/camel-checkstyle.xml b/buildingtools/src/main/resources/camel-checkstyle.xml
index 44e7c10..3b84c67 100644
--- a/buildingtools/src/main/resources/camel-checkstyle.xml
+++ b/buildingtools/src/main/resources/camel-checkstyle.xml
@@ -264,7 +264,7 @@ lengths, if/try depths, etc...
<module name="JUnitTestCase"/>
-->
<module name="ReturnCount">
- <property name="max" value="20"/>
+ <property name="max" value="21"/>
<property name="maxForVoid" value="25"/>
</module>
http://git-wip-us.apache.org/repos/asf/camel/blob/d97c9625/camel-core/src/main/docs/simple-language.adoc
----------------------------------------------------------------------
diff --git a/camel-core/src/main/docs/simple-language.adoc b/camel-core/src/main/docs/simple-language.adoc
index f13ed33..c8e428c 100644
--- a/camel-core/src/main/docs/simple-language.adoc
+++ b/camel-core/src/main/docs/simple-language.adoc
@@ -469,6 +469,8 @@ values)
|not contains |For testing if not contains in a string based value
+|~~ |For testing if contains by ignoring case sensitivity in a string based value
+
|regex |For matching against a given regular expression pattern defined as a
String value
http://git-wip-us.apache.org/repos/asf/camel/blob/d97c9625/camel-core/src/main/java/org/apache/camel/builder/PredicateBuilder.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/builder/PredicateBuilder.java b/camel-core/src/main/java/org/apache/camel/builder/PredicateBuilder.java
index 05c5673..b0511f8 100644
--- a/camel-core/src/main/java/org/apache/camel/builder/PredicateBuilder.java
+++ b/camel-core/src/main/java/org/apache/camel/builder/PredicateBuilder.java
@@ -330,6 +330,27 @@ public final class PredicateBuilder {
}
};
}
+
+ public static Predicate containsIgnoreCase(final Expression left, final Expression right) {
+ return new BinaryPredicateSupport(left, right) {
+
+ protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) {
+ if (leftValue == null && rightValue == null) {
+ // they are equal
+ return true;
+ } else if (leftValue == null || rightValue == null) {
+ // only one of them is null so they are not equal
+ return false;
+ }
+
+ return ObjectHelper.containsIgnoreCase(leftValue, rightValue);
+ }
+
+ protected String getOperationText() {
+ return "~~";
+ }
+ };
+ }
public static Predicate isNull(final Expression expression) {
return new BinaryPredicateSupport(expression, ExpressionBuilder.constantExpression(null)) {
http://git-wip-us.apache.org/repos/asf/camel/blob/d97c9625/camel-core/src/main/java/org/apache/camel/language/simple/SimpleTokenizer.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/language/simple/SimpleTokenizer.java b/camel-core/src/main/java/org/apache/camel/language/simple/SimpleTokenizer.java
index 4718cbe..b72f23d 100644
--- a/camel-core/src/main/java/org/apache/camel/language/simple/SimpleTokenizer.java
+++ b/camel-core/src/main/java/org/apache/camel/language/simple/SimpleTokenizer.java
@@ -63,6 +63,7 @@ public final class SimpleTokenizer {
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "is"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "not contains"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "contains"));
+ KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "~~"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "not regex"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "regex"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "not in"));
http://git-wip-us.apache.org/repos/asf/camel/blob/d97c9625/camel-core/src/main/java/org/apache/camel/language/simple/ast/BinaryExpression.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/language/simple/ast/BinaryExpression.java b/camel-core/src/main/java/org/apache/camel/language/simple/ast/BinaryExpression.java
index 4b6e821..e46b8c9 100644
--- a/camel-core/src/main/java/org/apache/camel/language/simple/ast/BinaryExpression.java
+++ b/camel-core/src/main/java/org/apache/camel/language/simple/ast/BinaryExpression.java
@@ -96,6 +96,8 @@ public class BinaryExpression extends BaseSimpleNode {
return createExpression(leftExp, rightExp, PredicateBuilder.contains(leftExp, rightExp));
} else if (operator == BinaryOperatorType.NOT_CONTAINS) {
return createExpression(leftExp, rightExp, PredicateBuilder.not(PredicateBuilder.contains(leftExp, rightExp)));
+ } else if (operator == BinaryOperatorType.CONTAINS_IGNORECASE) {
+ return createExpression(leftExp, rightExp, PredicateBuilder.containsIgnoreCase(leftExp, rightExp));
} else if (operator == BinaryOperatorType.IS || operator == BinaryOperatorType.NOT_IS) {
return createIsExpression(expression, leftExp, rightExp);
} else if (operator == BinaryOperatorType.REGEX || operator == BinaryOperatorType.NOT_REGEX) {
http://git-wip-us.apache.org/repos/asf/camel/blob/d97c9625/camel-core/src/main/java/org/apache/camel/language/simple/types/BinaryOperatorType.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/language/simple/types/BinaryOperatorType.java b/camel-core/src/main/java/org/apache/camel/language/simple/types/BinaryOperatorType.java
index 5a7751b..5ee1877 100644
--- a/camel-core/src/main/java/org/apache/camel/language/simple/types/BinaryOperatorType.java
+++ b/camel-core/src/main/java/org/apache/camel/language/simple/types/BinaryOperatorType.java
@@ -21,7 +21,8 @@ package org.apache.camel.language.simple.types;
*/
public enum BinaryOperatorType {
- EQ, EQ_IGNORE, GT, GTE, LT, LTE, NOT_EQ, CONTAINS, NOT_CONTAINS, REGEX, NOT_REGEX,
+ EQ, EQ_IGNORE, GT, GTE, LT, LTE, NOT_EQ, CONTAINS, NOT_CONTAINS,
+ CONTAINS_IGNORECASE, REGEX, NOT_REGEX,
IN, NOT_IN, IS, NOT_IS, RANGE, NOT_RANGE, STARTS_WITH, ENDS_WITH;
public static BinaryOperatorType asOperator(String text) {
@@ -43,6 +44,8 @@ public enum BinaryOperatorType {
return CONTAINS;
} else if ("not contains".equals(text)) {
return NOT_CONTAINS;
+ } else if ("~~".equals(text)) {
+ return CONTAINS_IGNORECASE;
} else if ("regex".equals(text)) {
return REGEX;
} else if ("not regex".equals(text)) {
@@ -86,6 +89,8 @@ public enum BinaryOperatorType {
return "contains";
} else if (operator == NOT_CONTAINS) {
return "not contains";
+ } else if (operator == CONTAINS_IGNORECASE) {
+ return "~~";
} else if (operator == REGEX) {
return "regex";
} else if (operator == NOT_REGEX) {
@@ -174,6 +179,8 @@ public enum BinaryOperatorType {
return null;
} else if (operator == NOT_CONTAINS) {
return null;
+ } else if (operator == CONTAINS_IGNORECASE) {
+ return null;
} else if (operator == REGEX) {
return new ParameterType[]{ParameterType.Literal, ParameterType.Function};
} else if (operator == NOT_REGEX) {
http://git-wip-us.apache.org/repos/asf/camel/blob/d97c9625/camel-core/src/main/java/org/apache/camel/util/ObjectHelper.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/util/ObjectHelper.java b/camel-core/src/main/java/org/apache/camel/util/ObjectHelper.java
index 829bcaf..73b6fae 100644
--- a/camel-core/src/main/java/org/apache/camel/util/ObjectHelper.java
+++ b/camel-core/src/main/java/org/apache/camel/util/ObjectHelper.java
@@ -195,6 +195,13 @@ public final class ObjectHelper {
public static boolean equal(Object a, Object b) {
return equal(a, b, false);
}
+
+ /**
+ * A helper method for comparing objects for equality while handling case insensitivity
+ */
+ public static boolean equalIgnoreCase(Object a, Object b) {
+ return equal(a, b, true);
+ }
/**
* A helper method for comparing objects for equality while handling nulls
@@ -647,6 +654,36 @@ public final class ObjectHelper {
}
return false;
}
+
+ /**
+ * Returns true if the collection contains the specified value by considering case insensitivity
+ */
+ public static boolean containsIgnoreCase(Object collectionOrArray, Object value) {
+ // favor String types
+ if (collectionOrArray != null && (collectionOrArray instanceof StringBuffer || collectionOrArray instanceof StringBuilder)) {
+ collectionOrArray = collectionOrArray.toString();
+ }
+ if (value != null && (value instanceof StringBuffer || value instanceof StringBuilder)) {
+ value = value.toString();
+ }
+
+ if (collectionOrArray instanceof Collection) {
+ Collection<?> collection = (Collection<?>)collectionOrArray;
+ return collection.contains(value);
+ } else if (collectionOrArray instanceof String && value instanceof String) {
+ String str = (String)collectionOrArray;
+ String subStr = (String)value;
+ return StringHelper.containsIgnoreCase(str, subStr);
+ } else {
+ Iterator<Object> iter = createIterator(collectionOrArray);
+ while (iter.hasNext()) {
+ if (equalIgnoreCase(value, iter.next())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
/**
* Creates an iterable over the value if the value is a collection, an
http://git-wip-us.apache.org/repos/asf/camel/blob/d97c9625/camel-core/src/main/java/org/apache/camel/util/StringHelper.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/util/StringHelper.java b/camel-core/src/main/java/org/apache/camel/util/StringHelper.java
index 635c07f..a9ce41f 100644
--- a/camel-core/src/main/java/org/apache/camel/util/StringHelper.java
+++ b/camel-core/src/main/java/org/apache/camel/util/StringHelper.java
@@ -672,5 +672,40 @@ public final class StringHelper {
return trimmed;
}
+
+ /**
+ * Checks if the src string contains what
+ *
+ * @param src is the source string to be checked
+ * @param what is the string which will be looked up in the src argument
+ * @return true/false
+ */
+ public static boolean containsIgnoreCase(String src, String what) {
+ if (src == null || what == null) {
+ return false;
+ }
+
+ final int length = what.length();
+ if (length == 0) {
+ return true; // Empty string is contained
+ }
+
+ final char firstLo = Character.toLowerCase(what.charAt(0));
+ final char firstUp = Character.toUpperCase(what.charAt(0));
+
+ for (int i = src.length() - length; i >= 0; i--) {
+ // Quick check before calling the more expensive regionMatches() method:
+ final char ch = src.charAt(i);
+ if (ch != firstLo && ch != firstUp) {
+ continue;
+ }
+
+ if (src.regionMatches(true, i, what, 0, length)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/d97c9625/camel-core/src/test/java/org/apache/camel/language/simple/SimpleOperatorTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/language/simple/SimpleOperatorTest.java b/camel-core/src/test/java/org/apache/camel/language/simple/SimpleOperatorTest.java
index e40154f..25de22e 100644
--- a/camel-core/src/test/java/org/apache/camel/language/simple/SimpleOperatorTest.java
+++ b/camel-core/src/test/java/org/apache/camel/language/simple/SimpleOperatorTest.java
@@ -328,6 +328,13 @@ public class SimpleOperatorTest extends LanguageTestSupport {
assertPredicate("${in.header.foo} not contains 'abc'", false);
assertPredicate("${in.header.foo} not contains 'def'", true);
}
+
+ public void testContainsIgnoreCase() throws Exception {
+ assertPredicate("${in.header.foo} ~~ 'A'", true);
+ assertPredicate("${in.header.foo} ~~ 'Ab'", true);
+ assertPredicate("${in.header.foo} ~~ 'Abc'", true);
+ assertPredicate("${in.header.foo} ~~ 'defG'", false);
+ }
public void testRegex() throws Exception {
assertPredicate("${in.header.foo} regex '^a..$'", true);
http://git-wip-us.apache.org/repos/asf/camel/blob/d97c9625/tests/camel-jmh/src/test/java/org/apache/camel/itest/jmh/ContainsIgnoreCaseTest.java
----------------------------------------------------------------------
diff --git a/tests/camel-jmh/src/test/java/org/apache/camel/itest/jmh/ContainsIgnoreCaseTest.java b/tests/camel-jmh/src/test/java/org/apache/camel/itest/jmh/ContainsIgnoreCaseTest.java
new file mode 100644
index 0000000..1a29133
--- /dev/null
+++ b/tests/camel-jmh/src/test/java/org/apache/camel/itest/jmh/ContainsIgnoreCaseTest.java
@@ -0,0 +1,85 @@
+/**
+ * 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.camel.itest.jmh;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.util.StringHelper;
+import org.junit.Test;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+import org.openjdk.jmh.runner.options.TimeValue;
+
+/**
+ * Tests the {@link StringHelper}.
+ * <p/>
+ * Thanks to this SO answer: https://stackoverflow.com/questions/30485856/how-to-run-jmh-from-inside-junit-tests
+ */
+public class ContainsIgnoreCaseTest {
+
+ @Test
+ public void launchBenchmark() throws Exception {
+ Options opt = new OptionsBuilder()
+ // Specify which benchmarks to run.
+ // You can be more specific if you'd like to run only one benchmark per test.
+ .include(this.getClass().getName() + ".*")
+ // Set the following options as needed
+ .mode(Mode.All)
+ .timeUnit(TimeUnit.MICROSECONDS)
+ .warmupTime(TimeValue.seconds(1))
+ .warmupIterations(2)
+ .measurementTime(TimeValue.seconds(1))
+ .measurementIterations(2)
+ .threads(2)
+ .forks(1)
+ .shouldFailOnError(true)
+ .shouldDoGC(true)
+ .build();
+
+ new Runner(opt).run();
+ }
+
+ // The JMH samples are the best documentation for how to use it
+ // http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/
+ @State(Scope.Thread)
+ public static class BenchmarkState {
+ @Setup(Level.Trial)
+ public void initialize() {
+ }
+ }
+
+ @Benchmark
+ @Measurement(batchSize = 1000000)
+ public void benchmark(BenchmarkState state, Blackhole bh) {
+ bh.consume(StringHelper.containsIgnoreCase("abc", "A"));
+ bh.consume(StringHelper.containsIgnoreCase("abc", "aB"));
+ bh.consume(StringHelper.containsIgnoreCase("abc", "aBc"));
+ bh.consume(StringHelper.containsIgnoreCase("abc", "ad"));
+ bh.consume(StringHelper.containsIgnoreCase("abc", "abD"));
+ bh.consume(StringHelper.containsIgnoreCase("abc", "ABD"));
+ }
+
+}