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 2020/01/31 06:13:03 UTC

[camel] branch master updated: CAMEL-14460: camel-core - Optimize and allow to turn off case insensitive headers

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 0f02d00  CAMEL-14460: camel-core - Optimize and allow to turn off case insensitive headers
0f02d00 is described below

commit 0f02d00a5c69eba2ae78beebee2f5f6266a8b698
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Jan 31 07:12:30 2020 +0100

    CAMEL-14460: camel-core - Optimize and allow to turn off case insensitive headers
---
 .../camel/blueprint/CamelContextFactoryBean.java   | 11 +++++
 .../camel/cdi/xml/CamelContextFactoryBean.java     | 12 +++++
 .../camel/spring/CamelContextFactoryBean.java      | 21 ++++++++
 .../org/apache/camel/RuntimeConfiguration.java     | 20 ++++++++
 .../camel/impl/engine/AbstractCamelContext.java    | 17 ++++++-
 .../camel/impl/engine/DefaultRouteContext.java     | 12 +++++
 .../core/xml/AbstractCamelContextFactoryBean.java  |  5 ++
 .../CamelCaseInsentiveHeadersFalseTest.java        | 56 +++++++++++++++++++++
 .../CamelCaseInsentiveHeadersTrueTest.java         | 57 ++++++++++++++++++++++
 .../camel/main/DefaultConfigurationConfigurer.java |  1 +
 .../camel/main/DefaultConfigurationProperties.java | 34 +++++++++++++
 .../camel-main-configuration-metadata.json         |  1 +
 12 files changed, 246 insertions(+), 1 deletion(-)

diff --git a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
index 02f3989..cb55279 100644
--- a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
+++ b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
@@ -125,6 +125,8 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu
     @XmlAttribute
     private String allowUseOriginalMessage;
     @XmlAttribute
+    private String caseInsensitiveHeaders;
+    @XmlAttribute
     private String runtimeEndpointRegistryEnabled;
     @XmlAttribute
     private String managementNamePattern;
@@ -454,6 +456,15 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu
     }
 
     @Override
+    public String getCaseInsensitiveHeaders() {
+        return caseInsensitiveHeaders;
+    }
+
+    public void setCaseInsensitiveHeaders(String caseInsensitiveHeaders) {
+        this.caseInsensitiveHeaders = caseInsensitiveHeaders;
+    }
+
+    @Override
     public String getRuntimeEndpointRegistryEnabled() {
         return runtimeEndpointRegistryEnabled;
     }
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
index 812a0c1..a945b37 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
@@ -126,6 +126,9 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Def
     private String allowUseOriginalMessage;
 
     @XmlAttribute
+    private String caseInsensitiveHeaders;
+
+    @XmlAttribute
     private String runtimeEndpointRegistryEnabled;
 
     @XmlAttribute
@@ -715,6 +718,15 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Def
     }
 
     @Override
+    public String getCaseInsensitiveHeaders() {
+        return caseInsensitiveHeaders;
+    }
+
+    public void setCaseInsensitiveHeaders(String caseInsensitiveHeaders) {
+        this.caseInsensitiveHeaders = caseInsensitiveHeaders;
+    }
+
+    @Override
     public String getRuntimeEndpointRegistryEnabled() {
         return runtimeEndpointRegistryEnabled;
     }
diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
index e9195b5..3429e9d 100644
--- a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
+++ b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
@@ -137,6 +137,8 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
     @XmlAttribute
     private String allowUseOriginalMessage;
     @XmlAttribute
+    private String caseInsensitiveHeaders;
+    @XmlAttribute
     private String runtimeEndpointRegistryEnabled;
     @XmlAttribute @Metadata(defaultValue = "#name#")
     private String managementNamePattern;
@@ -910,6 +912,25 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
     }
 
     @Override
+    public String getCaseInsensitiveHeaders() {
+        return caseInsensitiveHeaders;
+    }
+
+    /**
+     * Whether to use case sensitive or insensitive headers.
+     *
+     * Important: When using case sensitive (this is set to false).
+     * Then the map is case sensitive which means headers such as content-type and Content-Type are
+     * two different keys which can be a problem for some protocols such as HTTP based, which rely on case insensitive headers.
+     * However case sensitive implementations can yield faster performance. Therefore use case sensitive implementation with care.
+     *
+     * Default is true.
+     */
+    public void setCaseInsensitiveHeaders(String caseInsensitiveHeaders) {
+        this.caseInsensitiveHeaders = caseInsensitiveHeaders;
+    }
+
+    @Override
     public String getRuntimeEndpointRegistryEnabled() {
         return runtimeEndpointRegistryEnabled;
     }
diff --git a/core/camel-api/src/main/java/org/apache/camel/RuntimeConfiguration.java b/core/camel-api/src/main/java/org/apache/camel/RuntimeConfiguration.java
index e060773..4edbd32 100644
--- a/core/camel-api/src/main/java/org/apache/camel/RuntimeConfiguration.java
+++ b/core/camel-api/src/main/java/org/apache/camel/RuntimeConfiguration.java
@@ -234,4 +234,24 @@ public interface RuntimeConfiguration {
      */
     Boolean isAllowUseOriginalMessage();
 
+    /**
+     * Whether to use case sensitive or insensitive headers.
+     *
+     * Important: When using case sensitive (this is set to false).
+     * Then the map is case sensitive which means headers such as <tt>content-type</tt> and <tt>Content-Type</tt> are
+     * two different keys which can be a problem for some protocols such as HTTP based, which rely on case insensitive headers.
+     * However case sensitive implementations can yield faster performance. Therefore use case sensitive implementation with care.
+     */
+    Boolean isCaseInsensitiveHeaders();
+
+    /**
+     * Whether to use case sensitive or insensitive headers.
+     *
+     * Important: When using case sensitive (this is set to false).
+     * Then the map is case sensitive which means headers such as <tt>content-type</tt> and <tt>Content-Type</tt> are
+     * two different keys which can be a problem for some protocols such as HTTP based, which rely on case insensitive headers.
+     * However case sensitive implementations can yield faster performance. Therefore use case sensitive implementation with care.
+     */
+    void setCaseInsensitiveHeaders(Boolean caseInsensitiveHeaders);
+
 }
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index b4853da..31b7768 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -214,6 +214,7 @@ public abstract class AbstractCamelContext extends ServiceSupport implements Ext
     private Boolean useDataType = Boolean.FALSE;
     private Boolean useBreadcrumb = Boolean.FALSE;
     private Boolean allowUseOriginalMessage = Boolean.FALSE;
+    private Boolean caseInsensitiveHeaders = Boolean.TRUE;
     private Long delay;
     private ErrorHandlerFactory errorHandlerFactory;
     private Map<String, String> globalOptions = new HashMap<>();
@@ -3317,7 +3318,13 @@ public abstract class AbstractCamelContext extends ServiceSupport implements Ext
             // we want headers map to be created as then JVM can optimize using it as we use it per exchange/message
             synchronized (lock) {
                 if (headersMapFactory == null) {
-                    setHeadersMapFactory(createHeadersMapFactory());
+                    if (isCaseInsensitiveHeaders()) {
+                        // use factory to find the map factory to use
+                        setHeadersMapFactory(createHeadersMapFactory());
+                    } else {
+                        // case sensitive so we can use hash map
+                        setHeadersMapFactory(new HashMapHeadersMapFactory());
+                    }
                 }
             }
         }
@@ -3864,6 +3871,14 @@ public abstract class AbstractCamelContext extends ServiceSupport implements Ext
         return allowUseOriginalMessage != null && allowUseOriginalMessage;
     }
 
+    public Boolean isCaseInsensitiveHeaders() {
+        return caseInsensitiveHeaders != null && caseInsensitiveHeaders;
+    }
+
+    public void setCaseInsensitiveHeaders(Boolean caseInsensitiveHeaders) {
+        this.caseInsensitiveHeaders = caseInsensitiveHeaders;
+    }
+
     @Override
     public ExecutorServiceManager getExecutorServiceManager() {
         if (executorServiceManager == null) {
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultRouteContext.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultRouteContext.java
index 5397988..9cf4ad0 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultRouteContext.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultRouteContext.java
@@ -461,6 +461,18 @@ public class DefaultRouteContext implements RouteContext {
     }
 
     @Override
+    public Boolean isCaseInsensitiveHeaders() {
+        // can only be configured on CamelContext
+        return getCamelContext().isCaseInsensitiveHeaders();
+    }
+
+    @Override
+    public void setCaseInsensitiveHeaders(Boolean caseInsensitiveHeaders) {
+        // can only be configured on CamelContext
+        getCamelContext().setCaseInsensitiveHeaders(caseInsensitiveHeaders);
+    }
+
+    @Override
     public ShutdownRoute getShutdownRoute() {
         if (shutdownRoute != null) {
             return shutdownRoute;
diff --git a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
index e529703..8594aee 100644
--- a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
+++ b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
@@ -816,6 +816,8 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
 
     public abstract String getAllowUseOriginalMessage();
 
+    public abstract String getCaseInsensitiveHeaders();
+
     public abstract String getRuntimeEndpointRegistryEnabled();
 
     public abstract String getManagementNamePattern();
@@ -936,6 +938,9 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
         if (getAllowUseOriginalMessage() != null) {
             context.setAllowUseOriginalMessage(CamelContextHelper.parseBoolean(context, getAllowUseOriginalMessage()));
         }
+        if (getCaseInsensitiveHeaders() != null) {
+            context.setCaseInsensitiveHeaders(CamelContextHelper.parseBoolean(context, getCaseInsensitiveHeaders()));
+        }
         if (getRuntimeEndpointRegistryEnabled() != null) {
             context.getRuntimeEndpointRegistry().setEnabled(CamelContextHelper.parseBoolean(context, getRuntimeEndpointRegistryEnabled()));
         }
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/CamelCaseInsentiveHeadersFalseTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/CamelCaseInsentiveHeadersFalseTest.java
new file mode 100644
index 0000000..46c58c4
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/CamelCaseInsentiveHeadersFalseTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.apache.camel.CamelContext;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.Test;
+
+public class CamelCaseInsentiveHeadersFalseTest extends ContextTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        context.setCaseInsensitiveHeaders(false);
+        return context;
+    }
+
+    @Test
+    public void testCasesensitive() throws Exception {
+        getMockEndpoint("mock:foo").expectedBodiesReceived("Hello foo");
+        getMockEndpoint("mock:bar").expectedBodiesReceived("Hello bar");
+
+        template.sendBodyAndHeader("direct:start", "Hello foo", "foo", "123");
+        template.sendBodyAndHeader("direct:start", "Hello bar", "FOO", "456");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .choice()
+                        .when(header("foo")).to("mock:foo")
+                        .otherwise().to("mock:bar");
+            }
+        };
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/CamelCaseInsentiveHeadersTrueTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/CamelCaseInsentiveHeadersTrueTest.java
new file mode 100644
index 0000000..cdb4c87
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/CamelCaseInsentiveHeadersTrueTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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 org.apache.camel.CamelContext;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Test;
+
+public class CamelCaseInsentiveHeadersTrueTest extends ContextTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        context.setCaseInsensitiveHeaders(true);
+        return context;
+    }
+
+    @Test
+    public void testCasesensitive() throws Exception {
+        getMockEndpoint("mock:foo").expectedBodiesReceived("Hello foo", "Hello bar");
+        getMockEndpoint("mock:bar").expectedMessageCount(0);
+
+        template.sendBodyAndHeader("direct:start", "Hello foo", "foo", "123");
+        template.sendBodyAndHeader("direct:start", "Hello bar", "FOO", "456");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .choice()
+                        .when(header("foo")).to("mock:foo")
+                        .otherwise().to("mock:bar");
+            }
+        };
+    }
+}
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
index 95ad66b..69cc2d0 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
@@ -145,6 +145,7 @@ public final class DefaultConfigurationConfigurer {
         camelContext.setLogExhaustedMessageBody(config.isLogExhaustedMessageBody());
         camelContext.setAutoStartup(config.isAutoStartup());
         camelContext.setAllowUseOriginalMessage(config.isAllowUseOriginalMessage());
+        camelContext.setCaseInsensitiveHeaders(config.isCaseInsensitiveHeaders());
         camelContext.setUseBreadcrumb(config.isUseBreadcrumb());
         camelContext.setUseDataType(config.isUseDataType());
         camelContext.setUseMDCLogging(config.isUseMdcLogging());
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
index ecd7754..1a26864 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
@@ -59,6 +59,7 @@ public abstract class DefaultConfigurationProperties<T> {
     private boolean logExhaustedMessageBody;
     private boolean autoStartup = true;
     private boolean allowUseOriginalMessage;
+    private boolean caseInsensitiveHeaders = true;
     private boolean endpointRuntimeStatisticsEnabled;
     private boolean endpointLazyStartProducer;
     private boolean endpointBridgeErrorHandler;
@@ -527,6 +528,24 @@ public abstract class DefaultConfigurationProperties<T> {
         this.allowUseOriginalMessage = allowUseOriginalMessage;
     }
 
+    public boolean isCaseInsensitiveHeaders() {
+        return caseInsensitiveHeaders;
+    }
+
+    /**
+     * Whether to use case sensitive or insensitive headers.
+     *
+     * Important: When using case sensitive (this is set to false).
+     * Then the map is case sensitive which means headers such as content-type and Content-Type are
+     * two different keys which can be a problem for some protocols such as HTTP based, which rely on case insensitive headers.
+     * However case sensitive implementations can yield faster performance. Therefore use case sensitive implementation with care.
+     *
+     * Default is true.
+     */
+    public void setCaseInsensitiveHeaders(boolean caseInsensitiveHeaders) {
+        this.caseInsensitiveHeaders = caseInsensitiveHeaders;
+    }
+
     public boolean isEndpointRuntimeStatisticsEnabled() {
         return endpointRuntimeStatisticsEnabled;
     }
@@ -1205,6 +1224,21 @@ public abstract class DefaultConfigurationProperties<T> {
     }
 
     /**
+     * Whether to use case sensitive or insensitive headers.
+     *
+     * Important: When using case sensitive (this is set to false).
+     * Then the map is case sensitive which means headers such as content-type and Content-Type are
+     * two different keys which can be a problem for some protocols such as HTTP based, which rely on case insensitive headers.
+     * However case sensitive implementations can yield faster performance. Therefore use case sensitive implementation with care.
+     *
+     * Default is true.
+     */
+    public T withCaseInsensitiveHeaders(boolean caseInsensitiveHeaders) {
+        this.caseInsensitiveHeaders = caseInsensitiveHeaders;
+        return (T) this;
+    }
+
+    /**
      * Sets whether endpoint runtime statistics is enabled (gathers runtime usage of each incoming and outgoing endpoints).
      *
      * The default value is false.
diff --git a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
index 2d72e68..65b7e3c 100644
--- a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
+++ b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
@@ -19,6 +19,7 @@
     { "name": "camel.main.backlogTracing", "description": "Sets whether backlog tracing is enabled or not. Default is false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean" },
     { "name": "camel.main.beanIntrospectionExtendedStatistics", "description": "Sets whether bean introspection uses extended statistics. The default is false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean" },
     { "name": "camel.main.beanIntrospectionLoggingLevel", "description": "Sets the logging level used by bean introspection, logging activity of its usage. The default is TRACE.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "object", "javaType": "org.apache.camel.LoggingLevel", "enum": [ "ERROR", "WARN", "INFO", "DEBUG", "TRACE", "OFF" ] },
+    { "name": "camel.main.caseInsensitiveHeaders", "description": "Whether to use case sensitive or insensitive headers. Important: When using case sensitive (this is set to false). Then the map is case sensitive which means headers such as content-type and Content-Type are two different keys which can be a problem for some protocols such as HTTP based, which rely on case insensitive headers. However case sensitive implementations can yield faster performance. Therefore use case sensitiv [...]
     { "name": "camel.main.consumerTemplateCacheSize", "description": "Consumer template endpoints cache size.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "int", "defaultValue": 1000 },
     { "name": "camel.main.durationHitExitCode", "description": "Sets the exit code for the application if duration was hit", "sourceType": "org.apache.camel.main.MainConfigurationProperties", "type": "integer", "javaType": "int" },
     { "name": "camel.main.durationMaxIdleSeconds", "description": "To specify for how long time in seconds Camel can be idle before automatic terminating the JVM. You can use this to run Camel for a short while.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "int" },