You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2024/01/19 07:05:30 UTC

(camel) 01/01: CAMEL-20346: Comparison with type converters and stream caching should ensure the stream cache is reset so its re-readable afterwards. The contains function should also support file and stream cached input types

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch typecoerce
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 96ac8518d69216304e466fcf4e92e0e0e0d00614
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Jan 19 08:05:15 2024 +0100

    CAMEL-20346: Comparison with type converters and stream caching should ensure the stream cache is reset so its re-readable afterwards. The contains function should also support file and stream cached input types
---
 .../camel/processor/StreamCachingChoiceTest.java   | 68 +++++++++++++++++++++
 .../StreamCachingChoiceWithVariableTest.java       | 69 ++++++++++++++++++++++
 .../camel/processor/ThrottlerMethodCallTest.java   |  2 +-
 .../org/apache/camel/util/ObjectHelperTest.java    | 50 ++++++++++++++++
 .../test/resources/org/apache/camel/util/foo.txt   |  1 +
 .../test/resources/org/apache/camel/util/quote.txt |  2 +
 .../org/apache/camel/support/ObjectHelper.java     | 57 ++++++++++++++----
 7 files changed, 237 insertions(+), 12 deletions(-)

diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/StreamCachingChoiceTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/StreamCachingChoiceTest.java
new file mode 100644
index 00000000000..a3ff48268dd
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/StreamCachingChoiceTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.processor;
+
+import java.io.File;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.converter.stream.FileInputStreamCache;
+import org.junit.jupiter.api.Test;
+
+public class StreamCachingChoiceTest extends ContextTestSupport {
+
+    private static final String TEST_FILE = "src/test/resources/org/apache/camel/converter/stream/test.xml";
+
+    @Test
+    public void testStreamCaching() throws Exception {
+        getMockEndpoint("mock:paris").expectedMessageCount(0);
+        getMockEndpoint("mock:madrid").expectedMessageCount(0);
+        getMockEndpoint("mock:london").expectedMessageCount(1);
+        getMockEndpoint("mock:other").expectedMessageCount(1);
+
+        File file = new File(TEST_FILE);
+        FileInputStreamCache cache = new FileInputStreamCache(file);
+        template.sendBody("direct:start", cache);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:start")
+                        .choice()
+                            .when().simple("${body} contains 'Paris'")
+                                .to("mock:paris")
+                            .when().simple("${body} contains 'London'")
+                                .to("mock:london")
+                            .otherwise()
+                                .to("mock:other")
+                        .end()
+                        .choice()
+                            .when().simple("${body} contains 'Paris'")
+                                .to("mock:paris")
+                            .when().simple("${body} contains 'Madrid'")
+                                .to("mock:madrid")
+                            .otherwise()
+                                .to("mock:other")
+                        .end();
+            }
+        };
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/StreamCachingChoiceWithVariableTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/StreamCachingChoiceWithVariableTest.java
new file mode 100644
index 00000000000..a24c1e6271c
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/StreamCachingChoiceWithVariableTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.processor;
+
+import java.io.File;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.converter.stream.FileInputStreamCache;
+import org.junit.jupiter.api.Test;
+
+public class StreamCachingChoiceWithVariableTest extends ContextTestSupport {
+
+    private static final String TEST_FILE = "src/test/resources/org/apache/camel/converter/stream/test.xml";
+
+    @Test
+    public void testStreamCaching() throws Exception {
+        getMockEndpoint("mock:paris").expectedMessageCount(0);
+        getMockEndpoint("mock:madrid").expectedMessageCount(0);
+        getMockEndpoint("mock:london").expectedMessageCount(1);
+        getMockEndpoint("mock:other").expectedMessageCount(1);
+
+        File file = new File(TEST_FILE);
+        FileInputStreamCache cache = new FileInputStreamCache(file);
+        template.sendBody("direct:start", cache);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:start")
+                        .setVariable("foo").simple("${body}")
+                        .choice()
+                            .when().simple("${variable:foo} contains 'Paris'")
+                                .to("mock:paris")
+                            .when().simple("${variable:foo} contains 'London'")
+                                .to("mock:london")
+                            .otherwise()
+                                .to("mock:other")
+                        .end()
+                        .choice()
+                            .when().simple("${variable:foo} contains 'Paris'")
+                                .to("mock:paris")
+                            .when().simple("${variable:foo} contains 'Madrid'")
+                                .to("mock:madrid")
+                            .otherwise()
+                                .to("mock:other")
+                        .end();
+            }
+        };
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/ThrottlerMethodCallTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/ThrottlerMethodCallTest.java
index 16f59048b60..14aa716a72f 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/ThrottlerMethodCallTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/ThrottlerMethodCallTest.java
@@ -70,7 +70,7 @@ public class ThrottlerMethodCallTest extends ContextTestSupport {
     }
 
     @Test
-    public void testConfigurationWithMethodCallExpression()  {
+    public void testConfigurationWithMethodCallExpression() {
         for (int i = 0; i < messageCount; i++) {
             executor.execute(() -> template.sendBody("direct:expressionMethod", "<message>payload</message>"));
         }
diff --git a/core/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java b/core/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java
index e05d74e0ecf..b0fd15074a1 100644
--- a/core/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.util;
 
+import java.io.File;
 import java.io.InputStream;
 import java.lang.reflect.Method;
 import java.net.URL;
@@ -44,6 +45,7 @@ import org.apache.camel.component.bean.MyOtherFooBean.AbstractClassSize;
 import org.apache.camel.component.bean.MyOtherFooBean.Clazz;
 import org.apache.camel.component.bean.MyOtherFooBean.InterfaceSize;
 import org.apache.camel.component.bean.MyStaticClass;
+import org.apache.camel.converter.stream.FileInputStreamCache;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.DefaultMessage;
@@ -124,6 +126,54 @@ public class ObjectHelperTest {
         }
     }
 
+    @Test
+    void testContainsStreamCaching() throws Exception {
+        try (CamelContext context = new DefaultCamelContext()) {
+            context.start();
+            TypeConverter tc = context.getTypeConverter();
+
+            File file = new File("src/test/resources/org/apache/camel/util/quote.txt");
+            FileInputStreamCache data = new FileInputStreamCache(file);
+
+            assertTrue(ObjectHelper.typeCoerceContains(tc, data, "foo", true));
+            assertTrue(ObjectHelper.typeCoerceContains(tc, data, "FOO", true));
+            assertFalse(ObjectHelper.typeCoerceContains(tc, data, "FOO", false));
+
+            assertTrue(ObjectHelper.typeCoerceContains(tc, data, "foo", true));
+            assertTrue(ObjectHelper.typeCoerceContains(tc, data, "FOO", true));
+            assertFalse(ObjectHelper.typeCoerceContains(tc, data, "FOO", false));
+
+            assertTrue(ObjectHelper.typeCoerceContains(tc, "foo", "foo", true));
+            assertFalse(ObjectHelper.typeCoerceContains(tc, data, "xyz", true));
+            assertFalse(ObjectHelper.typeCoerceContains(tc, data, "xyz", true));
+            assertFalse(ObjectHelper.typeCoerceContains(tc, "foo", "xyz", true));
+        }
+    }
+
+    @Test
+    void testEqualsStreamCaching() throws Exception {
+        try (CamelContext context = new DefaultCamelContext()) {
+            context.start();
+            TypeConverter tc = context.getTypeConverter();
+
+            File file = new File("src/test/resources/org/apache/camel/util/foo.txt");
+            FileInputStreamCache data = new FileInputStreamCache(file);
+
+            assertTrue(ObjectHelper.typeCoerceEquals(tc, data, "foo", true));
+            assertTrue(ObjectHelper.typeCoerceEquals(tc, data, "FOO", true));
+            assertFalse(ObjectHelper.typeCoerceEquals(tc, data, "FOO", false));
+
+            assertTrue(ObjectHelper.typeCoerceEquals(tc, data, "foo", true));
+            assertTrue(ObjectHelper.typeCoerceEquals(tc, data, "FOO", true));
+            assertFalse(ObjectHelper.typeCoerceEquals(tc, data, "FOO", false));
+
+            assertTrue(ObjectHelper.typeCoerceEquals(tc, "foo", "foo", true));
+            assertFalse(ObjectHelper.typeCoerceEquals(tc, data, "xyz", true));
+            assertFalse(ObjectHelper.typeCoerceEquals(tc, data, "xyz", true));
+            assertFalse(ObjectHelper.typeCoerceEquals(tc, "foo", "xyz", true));
+        }
+    }
+
     @Test
     void testContainsStringBuilder() throws Exception {
         try (CamelContext context = new DefaultCamelContext()) {
diff --git a/core/camel-core/src/test/resources/org/apache/camel/util/foo.txt b/core/camel-core/src/test/resources/org/apache/camel/util/foo.txt
new file mode 100644
index 00000000000..19102815663
--- /dev/null
+++ b/core/camel-core/src/test/resources/org/apache/camel/util/foo.txt
@@ -0,0 +1 @@
+foo
\ No newline at end of file
diff --git a/core/camel-core/src/test/resources/org/apache/camel/util/quote.txt b/core/camel-core/src/test/resources/org/apache/camel/util/quote.txt
new file mode 100644
index 00000000000..06564a61da9
--- /dev/null
+++ b/core/camel-core/src/test/resources/org/apache/camel/util/quote.txt
@@ -0,0 +1,2 @@
+Hello foo how are you?
+Thank you I am going to the bar now.
\ No newline at end of file
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java
index c1876c76482..3c0d30cb902 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.support;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.lang.reflect.Array;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -45,7 +47,9 @@ import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.Ordered;
 import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.StreamCache;
 import org.apache.camel.TypeConverter;
+import org.apache.camel.WrappedFile;
 import org.apache.camel.util.ReflectionHelper;
 import org.apache.camel.util.Scanner;
 import org.apache.camel.util.StringHelper;
@@ -145,15 +149,28 @@ public final class ObjectHelper {
         }
 
         // convert left to right
-        Object value = converter.tryConvertTo(rightValue.getClass(), leftValue);
-        final boolean isEqualLeftToRight = org.apache.camel.util.ObjectHelper.equal(value, rightValue, ignoreCase);
-        if (isEqualLeftToRight) {
-            return true;
-        }
+        StreamCache sc = null;
+        try {
+            if (leftValue instanceof StreamCache) {
+                sc = (StreamCache) leftValue;
+            }
+            Object value = converter.tryConvertTo(rightValue.getClass(), leftValue);
+            final boolean isEqualLeftToRight = org.apache.camel.util.ObjectHelper.equal(value, rightValue, ignoreCase);
+            if (isEqualLeftToRight) {
+                return true;
+            }
 
-        // convert right to left
-        value = converter.tryConvertTo(leftValue.getClass(), rightValue);
-        return org.apache.camel.util.ObjectHelper.equal(leftValue, value, ignoreCase);
+            // convert right to left
+            if (rightValue instanceof StreamCache) {
+                sc = (StreamCache) rightValue;
+            }
+            value = converter.tryConvertTo(leftValue.getClass(), rightValue);
+            return org.apache.camel.util.ObjectHelper.equal(leftValue, value, ignoreCase);
+        } finally {
+            if (sc != null) {
+                sc.reset();
+            }
+        }
     }
 
     private static boolean booleanStringComparison(Boolean leftBool, String rightValue) {
@@ -964,14 +981,32 @@ public final class ObjectHelper {
      */
     public static boolean typeCoerceContains(
             TypeConverter typeConverter, Object collectionOrArray, Object value, boolean ignoreCase) {
+
+        // unwrap file
+        if (collectionOrArray instanceof WrappedFile<?> wf) {
+            collectionOrArray = wf.getBody();
+        }
+        if (collectionOrArray instanceof StreamCache sc) {
+            try {
+                ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                sc.writeTo(bos);
+                collectionOrArray = bos.toByteArray();
+            } catch (IOException e) {
+                // ignore
+            } finally {
+                sc.reset();
+            }
+        }
         // favor String types
+        if (value instanceof StringBuffer || value instanceof StringBuilder) {
+            value = value.toString();
+        }
         if (collectionOrArray instanceof StringBuffer || collectionOrArray instanceof StringBuilder) {
             collectionOrArray = collectionOrArray.toString();
         }
-        if (value instanceof StringBuffer || value instanceof StringBuilder) {
-            value = value.toString();
+        if (collectionOrArray instanceof byte[] arr) {
+            collectionOrArray = new String(arr);
         }
-
         if (collectionOrArray instanceof Collection) {
             Collection<?> collection = (Collection<?>) collectionOrArray;
             if (ignoreCase) {