CAMEL-8113: Optimize type converter registry.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/5cfa913c Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/5cfa913c Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/5cfa913c Branch: refs/heads/master Commit: 5cfa913c265c7b4b3aaa5d08b7ee7f531071671f Parents: 9cd39ab Author: Claus Ibsen <davscl...@apache.org> Authored: Thu Dec 18 16:28:11 2014 +0100 Committer: Claus Ibsen <davscl...@apache.org> Committed: Thu Dec 18 21:27:57 2014 +0100 ---------------------------------------------------------------------- .../apache/camel/builder/ExpressionBuilder.java | 11 ++- .../apache/camel/component/bean/MethodInfo.java | 9 ++- .../camel/language/bean/BeanExpression.java | 7 +- .../apache/camel/support/ExpressionAdapter.java | 4 ++ .../processor/TransformMethodCallTest.java | 48 ------------- ...peConverterRegistryStatsPerformanceTest.java | 76 ++++++++++++++++++++ 6 files changed, 101 insertions(+), 54 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/5cfa913c/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java b/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java index 20f00b9..91c226c 100644 --- a/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java +++ b/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java @@ -1001,9 +1001,14 @@ public final class ExpressionBuilder { } // if its a bean invocation then if it has no arguments then it should be threaded as null body allowed - BeanInvocation bi = exchange.getIn().getBody(BeanInvocation.class); - if (bi != null && (bi.getArgs() == null || bi.getArgs().length == 0 || bi.getArgs()[0] == null)) { - return null; + if (exchange.getIn().getBody() instanceof BeanInvocation) { + // BeanInvocation would be stored directly as the message body + // do not force any type conversion attempts as it would just be unnecessary and cost a bit performance + // so a regular instanceof check is sufficient + BeanInvocation bi = (BeanInvocation) exchange.getIn().getBody(); + if (bi.getArgs() == null || bi.getArgs().length == 0 || bi.getArgs()[0] == null) { + return null; + } } } http://git-wip-us.apache.org/repos/asf/camel/blob/5cfa913c/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java b/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java index 9236cd0..aaf3cf0 100644 --- a/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java +++ b/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java @@ -594,9 +594,14 @@ public class MethodInfo { // use object first to avoid type conversion so we know if there is a value or not Object result = expression.evaluate(exchange, Object.class); if (result != null) { - // we got a value now try to convert it to the expected type try { - answer = exchange.getContext().getTypeConverter().mandatoryConvertTo(parameterType, result); + if (parameterType.isInstance(result)) { + // optimize if the value is already the same type + answer = result; + } else { + // we got a value now try to convert it to the expected type + answer = exchange.getContext().getTypeConverter().mandatoryConvertTo(parameterType, result); + } if (LOG.isTraceEnabled()) { LOG.trace("Parameter #{} evaluated as: {} type: ", new Object[]{index, answer, ObjectHelper.type(answer)}); } http://git-wip-us.apache.org/repos/asf/camel/blob/5cfa913c/camel-core/src/main/java/org/apache/camel/language/bean/BeanExpression.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/language/bean/BeanExpression.java b/camel-core/src/main/java/org/apache/camel/language/bean/BeanExpression.java index 3cbc2fa..f5cc981 100644 --- a/camel-core/src/main/java/org/apache/camel/language/bean/BeanExpression.java +++ b/camel-core/src/main/java/org/apache/camel/language/bean/BeanExpression.java @@ -130,7 +130,12 @@ public class BeanExpression implements Expression, Predicate { public <T> T evaluate(Exchange exchange, Class<T> type) { Object result = evaluate(exchange); - return exchange.getContext().getTypeConverter().convertTo(type, exchange, result); + if (Object.class == type) { + // do not use type converter if type is Object (optimize) + return (T) result; + } else { + return exchange.getContext().getTypeConverter().convertTo(type, exchange, result); + } } public boolean matches(Exchange exchange) { http://git-wip-us.apache.org/repos/asf/camel/blob/5cfa913c/camel-core/src/main/java/org/apache/camel/support/ExpressionAdapter.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/support/ExpressionAdapter.java b/camel-core/src/main/java/org/apache/camel/support/ExpressionAdapter.java index d8e43a9..3344eab 100644 --- a/camel-core/src/main/java/org/apache/camel/support/ExpressionAdapter.java +++ b/camel-core/src/main/java/org/apache/camel/support/ExpressionAdapter.java @@ -34,6 +34,10 @@ public abstract class ExpressionAdapter extends ExpressionSupport { public <T> T evaluate(Exchange exchange, Class<T> type) { Object value = evaluate(exchange); + if (Object.class == type) { + // do not use type converter if type is Object (optimize) + return (T) value; + } return exchange.getContext().getTypeConverter().convertTo(type, exchange, value); } http://git-wip-us.apache.org/repos/asf/camel/blob/5cfa913c/camel-core/src/test/java/org/apache/camel/processor/TransformMethodCallTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/processor/TransformMethodCallTest.java b/camel-core/src/test/java/org/apache/camel/processor/TransformMethodCallTest.java deleted file mode 100644 index 6144e3c..0000000 --- a/camel-core/src/test/java/org/apache/camel/processor/TransformMethodCallTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * 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.ContextTestSupport; -import org.apache.camel.builder.RouteBuilder; - -/** - * @version - */ -public class TransformMethodCallTest extends ContextTestSupport { - - public void testTransform() throws Exception { - getMockEndpoint("mock:result").expectedBodiesReceived("Hello World"); - - template.sendBody("direct:start", "World"); - - assertMockEndpointsSatisfied(); - } - - protected RouteBuilder createRouteBuilder() { - return new RouteBuilder() { - public void configure() { - from("direct:start") - .transform().method(TransformMethodCallTest.class, "transformMe") - .to("mock:result"); - } - }; - } - - public String transformMe(String in) { - return "Hello " + in; - } -} http://git-wip-us.apache.org/repos/asf/camel/blob/5cfa913c/camel-core/src/test/java/org/apache/camel/processor/TypeConverterRegistryStatsPerformanceTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/processor/TypeConverterRegistryStatsPerformanceTest.java b/camel-core/src/test/java/org/apache/camel/processor/TypeConverterRegistryStatsPerformanceTest.java new file mode 100644 index 0000000..077f0f2 --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/processor/TypeConverterRegistryStatsPerformanceTest.java @@ -0,0 +1,76 @@ +/** + * 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; + +/** + * @version + */ +public class TypeConverterRegistryStatsPerformanceTest extends ContextTestSupport { + + private int size = 1000; + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + context.setTypeConverterStatisticsEnabled(true); + return context; + } + + public void testTransform() throws Exception { + long attempt = context.getTypeConverterRegistry().getStatistics().getAttemptCounter(); + long failed = context.getTypeConverterRegistry().getStatistics().getFailedCounter(); + long hit = context.getTypeConverterRegistry().getStatistics().getHitCounter(); + long miss = context.getTypeConverterRegistry().getStatistics().getMissCounter(); + + getMockEndpoint("mock:result").expectedMessageCount(size); + + for (int i = 0; i < size; i++) { + template.sendBody("direct:start", "World"); + } + + assertMockEndpointsSatisfied(); + + long attempt2 = context.getTypeConverterRegistry().getStatistics().getAttemptCounter(); + long failed2 = context.getTypeConverterRegistry().getStatistics().getFailedCounter(); + long hit2 = context.getTypeConverterRegistry().getStatistics().getHitCounter(); + long miss2 = context.getTypeConverterRegistry().getStatistics().getMissCounter(); + + log.info("Attempt: before={}, after={}, delta={}", new Object[]{attempt, attempt2, attempt2 - attempt}); + log.info("Failed: before={}, after={}, delta={}", new Object[]{failed, failed2, failed2 - failed}); + log.info("Hit: before={}, after={}, delta={}", new Object[]{hit, hit2, hit2 - hit}); + log.info("Miss: before={}, after={}, delta={}", new Object[]{miss, miss2, miss2 - miss}); + } + + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:start") + .transform().method(TypeConverterRegistryStatsPerformanceTest.class, "transformMe") +// .bean(TypeConverterRegistryStatsPerformanceTest.class, "transformMe") + .to("mock:result"); + } + }; + } + + public String transformMe(String in) { + return "Hello " + in; + } +}