This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch var in repository https://gitbox.apache.org/repos/asf/camel.git
commit a1da0560b6104fb2191dc46e2e7a86a252040138 Author: Claus Ibsen <[email protected]> AuthorDate: Thu Dec 28 13:19:45 2023 +0100 CAMEL-19749: Add variables as concept to Camel --- .../camel-bean/src/main/docs/bean-language.adoc | 2 +- .../bean/AbstractCamelInvocationHandler.java | 14 +++ .../org/apache/camel/component/bean/BeanInfo.java | 7 ++ .../src/main/java/org/apache/camel/Variable.java | 39 +++++++ .../src/main/java/org/apache/camel/Variables.java | 34 ++++++ .../component/bean/BeanPipelineVariablesTest.java | 96 +++++++++++++++++ ...eanWithPropertiesAndVariablesInjectionTest.java | 97 +++++++++++++++++ .../bean/BeanWithVariablesAndBodyInject3Test.java | 87 ++++++++++++++++ .../BeanWithVariablesAndBodyInjectionTest.java | 99 ++++++++++++++++++ .../camel/processor/MethodFilterVariableTest.java | 74 +++++++++++++ .../camel/support/builder/ExpressionBuilder.java | 115 +++++++++++++++++++++ .../ROOT/pages/parameter-binding-annotations.adoc | 9 +- 12 files changed, 671 insertions(+), 2 deletions(-) diff --git a/components/camel-bean/src/main/docs/bean-language.adoc b/components/camel-bean/src/main/docs/bean-language.adoc index 85996a113ab..f7138e4e5ce 100644 --- a/components/camel-bean/src/main/docs/bean-language.adoc +++ b/components/camel-bean/src/main/docs/bean-language.adoc @@ -76,7 +76,7 @@ public boolean isGoldCustomer(String body) {...} === Using Annotations for bean integration You can also use the xref:manual::bean-integration.adoc[Bean Integration] -annotations, such as `@Header`, `@Body` etc +annotations, such as `@Header`, `@Body`, `@Variable` etc [source,java] ---- diff --git a/components/camel-bean/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java b/components/camel-bean/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java index b7cc688765e..4cd04ab2b37 100644 --- a/components/camel-bean/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java +++ b/components/camel-bean/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java @@ -43,6 +43,8 @@ import org.apache.camel.Headers; import org.apache.camel.InvalidPayloadException; import org.apache.camel.Producer; import org.apache.camel.RuntimeCamelException; +import org.apache.camel.Variable; +import org.apache.camel.Variables; import org.apache.camel.support.DefaultExchange; import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.StringHelper; @@ -109,6 +111,8 @@ public abstract class AbstractCamelInvocationHandler implements InvocationHandle for (Parameter parameter : method.getParameters()) { if (parameter.isAnnotationPresent(Header.class) || parameter.isAnnotationPresent(Headers.class) + || parameter.isAnnotationPresent(Variable.class) + || parameter.isAnnotationPresent(Variables.class) || parameter.isAnnotationPresent(ExchangeProperty.class) || parameter.isAnnotationPresent(Body.class)) { canUseBinding = true; @@ -139,6 +143,16 @@ public abstract class AbstractCamelInvocationHandler implements InvocationHandle if (map != null) { exchange.getIn().getHeaders().putAll(map); } + } else if (ann.annotationType().isAssignableFrom(Variable.class)) { + Variable variable = (Variable) ann; + String name = variable.value(); + exchange.setVariable(name, value); + } else if (ann.annotationType().isAssignableFrom(Variables.class)) { + Map<String, Object> map + = exchange.getContext().getTypeConverter().tryConvertTo(Map.class, exchange, value); + if (map != null) { + exchange.getVariables().putAll(map); + } } else if (ann.annotationType().isAssignableFrom(ExchangeProperty.class)) { ExchangeProperty ep = (ExchangeProperty) ann; String name = ep.value(); diff --git a/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java b/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java index 5e0a27b908f..99b646dcaa3 100644 --- a/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java +++ b/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java @@ -42,6 +42,8 @@ import org.apache.camel.Header; import org.apache.camel.Headers; import org.apache.camel.Message; import org.apache.camel.PropertyInject; +import org.apache.camel.Variable; +import org.apache.camel.Variables; import org.apache.camel.support.ObjectHelper; import org.apache.camel.support.builder.ExpressionBuilder; import org.apache.camel.support.language.AnnotationExpressionFactory; @@ -1012,6 +1014,11 @@ public class BeanInfo { return ExpressionBuilder.headerExpression(headerAnnotation.value()); } else if (annotation instanceof Headers) { return ExpressionBuilder.headersExpression(); + } else if (annotation instanceof Variable) { + Variable variableAnnotation = (Variable) annotation; + return ExpressionBuilder.variableExpression(variableAnnotation.value()); + } else if (annotation instanceof Variables) { + return ExpressionBuilder.variablesExpression(); } else if (annotation instanceof ExchangeException) { return ExpressionBuilder.exchangeExceptionExpression(CastUtils.cast(parameterType, Exception.class)); } else if (annotation instanceof PropertyInject) { diff --git a/core/camel-api/src/main/java/org/apache/camel/Variable.java b/core/camel-api/src/main/java/org/apache/camel/Variable.java new file mode 100644 index 00000000000..e91a29b749a --- /dev/null +++ b/core/camel-api/src/main/java/org/apache/camel/Variable.java @@ -0,0 +1,39 @@ +/* + * 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; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks a parameter as being a variable + * + * @see Exchange#getVariable(String) + */ +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Target({ ElementType.PARAMETER }) +public @interface Variable { + + /** + * Name of variable + */ + String value(); +} diff --git a/core/camel-api/src/main/java/org/apache/camel/Variables.java b/core/camel-api/src/main/java/org/apache/camel/Variables.java new file mode 100644 index 00000000000..30e9ccfd7f2 --- /dev/null +++ b/core/camel-api/src/main/java/org/apache/camel/Variables.java @@ -0,0 +1,34 @@ +/* + * 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; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks a parameter as being an injection point of the variables + * + * @see Exchange#getVariables() + */ +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Target({ ElementType.PARAMETER }) +public @interface Variables { +} diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanPipelineVariablesTest.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanPipelineVariablesTest.java new file mode 100644 index 00000000000..02355fd2da8 --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanPipelineVariablesTest.java @@ -0,0 +1,96 @@ +/* + * 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.component.bean; + +import java.util.Map; + +import org.apache.camel.Body; +import org.apache.camel.ContextTestSupport; +import org.apache.camel.Exchange; +import org.apache.camel.Variables; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spi.Registry; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * Unit test of bean can propagate headers in a pipeline + */ +public class BeanPipelineVariablesTest extends ContextTestSupport { + + @Test + public void testBeanInPipeline() throws Exception { + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedBodiesReceived("Hello World from James"); + mock.expectedVariableReceived("from", "James"); + + template.sendBodyAndHeader("direct:input", "Hello World", "from", "Claus"); + mock.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + public void configure() throws Exception { + from("direct:input").pipeline("bean:foo", "bean:bar?method=usingExchange", "bean:baz").to("mock:result"); + } + }; + } + + @Override + protected Registry createRegistry() throws Exception { + Registry answer = super.createRegistry(); + answer.bind("foo", new FooBean()); + answer.bind("bar", new BarBean()); + answer.bind("baz", new BazBean()); + return answer; + } + + public static class FooBean { + public void onlyPlainBody(Object body) { + assertEquals("Hello World", body); + } + } + + public static class BarBean { + public void doNotUseMe(String body) { + fail("Should not invoce me"); + } + + public void usingExchange(Exchange exchange) { + String body = exchange.getIn().getBody(String.class); + assertEquals("Hello World", body); + assertEquals("Claus", exchange.getIn().getHeader("from")); + exchange.setVariable("from", "James"); + exchange.getMessage().setBody("Hello World from James"); + } + } + + public static class BazBean { + public void doNotUseMe(String body) { + fail("Should not invoce me"); + } + + public void withAnnotations(@Variables Map<String, Object> variables, @Body String body) { + assertEquals("Hello World from James", body); + assertEquals("James", variables.get("from")); + } + } +} diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithPropertiesAndVariablesInjectionTest.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithPropertiesAndVariablesInjectionTest.java new file mode 100644 index 00000000000..b627ce63ead --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithPropertiesAndVariablesInjectionTest.java @@ -0,0 +1,97 @@ +/* + * 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.component.bean; + +import java.util.Map; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.Exchange; +import org.apache.camel.ExchangeProperties; +import org.apache.camel.Message; +import org.apache.camel.Processor; +import org.apache.camel.Variables; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.processor.BeanRouteTest; +import org.apache.camel.spi.Registry; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class BeanWithPropertiesAndVariablesInjectionTest extends ContextTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(BeanRouteTest.class); + protected MyBean myBean = new MyBean(); + + @Test + public void testSendMessage() throws Exception { + template.send("direct:in", new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.setProperty("p1", "abc"); + exchange.setProperty("p2", 123); + + Message in = exchange.getIn(); + exchange.setVariable("h1", "xyz"); + exchange.setVariable("h2", 456); + } + }); + + Map<?, ?> foo = myBean.foo; + Map<?, ?> bar = myBean.bar; + assertNotNull(foo, "myBean.foo"); + assertNotNull(bar, "myBean.bar"); + + assertEquals("abc", foo.get("p1"), "foo.p1"); + assertEquals(123, foo.get("p2"), "foo.p2"); + + assertEquals("xyz", bar.get("h1"), "bar.h1"); + assertEquals(456, bar.get("h2"), "bar.h2"); + } + + @Override + protected Registry createRegistry() throws Exception { + Registry answer = super.createRegistry(); + answer.bind("myBean", myBean); + return answer; + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:in").bean("myBean"); + } + }; + } + + public static class MyBean { + public Map<?, ?> foo; + public Map<?, ?> bar; + + @Override + public String toString() { + return "MyBean[foo: " + foo + " bar: " + bar + "]"; + } + + public void myMethod(@ExchangeProperties Map<?, ?> foo, @Variables Map<?, ?> bar) { + this.foo = foo; + this.bar = bar; + LOG.info("myMethod() method called on {}", this); + } + } +} diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInject3Test.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInject3Test.java new file mode 100644 index 00000000000..795f0ca46bd --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInject3Test.java @@ -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.camel.component.bean; + +import java.util.Map; + +import org.apache.camel.Body; +import org.apache.camel.ContextTestSupport; +import org.apache.camel.Variables; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spi.Registry; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class BeanWithVariablesAndBodyInject3Test extends ContextTestSupport { + private final MyBean myBean = new MyBean(); + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:start").to("bean:myBean?method=doSomething").to("mock:finish"); + } + }; + } + + @Test + public void testInOnly() throws Exception { + MockEndpoint end = getMockEndpoint("mock:finish"); + end.expectedBodiesReceived("Hello!"); + + sendBody("direct:start", "Test Input"); + + assertMockEndpointsSatisfied(); + + assertNotNull(end.getExchanges().get(0).getIn().getBody()); + assertEquals("Hello!", end.getExchanges().get(0).getIn().getBody()); + } + + @Test + public void testInOut() throws Exception { + MockEndpoint end = getMockEndpoint("mock:finish"); + end.expectedBodiesReceived("Hello!"); + end.expectedVariableReceived("out", 123); + + String out = template.requestBody("direct:start", "Test Input", String.class); + assertEquals("Hello!", out); + + assertMockEndpointsSatisfied(); + + assertNotNull(end.getExchanges().get(0).getIn().getBody()); + assertEquals("Hello!", end.getExchanges().get(0).getIn().getBody()); + assertEquals(123, end.getExchanges().get(0).getVariable("out")); + } + + @Override + protected Registry createRegistry() throws Exception { + Registry answer = super.createRegistry(); + answer.bind("myBean", myBean); + return answer; + } + + public static class MyBean { + + public String doSomething(@Body String body, @Variables Map<String, Object> variables) { + variables.put("out", 123); + return "Hello!"; + } + } +} diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInjectionTest.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInjectionTest.java new file mode 100644 index 00000000000..e1245c0cdeb --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInjectionTest.java @@ -0,0 +1,99 @@ +/* + * 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.component.bean; + +import java.util.Map; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.Processor; +import org.apache.camel.Variables; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.processor.BeanRouteTest; +import org.apache.camel.spi.Registry; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + +public class BeanWithVariablesAndBodyInjectionTest extends ContextTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(BeanRouteTest.class); + protected MyBean myBean = new MyBean(); + + @Test + public void testSendMessage() throws Exception { + template.send("direct:in", new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.setProperty("p1", "abc"); + exchange.setProperty("p2", 123); + + Message in = exchange.getIn(); + exchange.setVariable("h1", "xyz"); + exchange.setVariable("h2", 456); + in.setBody("TheBody"); + } + }); + + Map<String, Object> foo = myBean.variables; + assertNotNull(foo, "myBean.foo"); + + assertEquals("xyz", foo.get("h1"), "foo.h1"); + assertEquals(456, foo.get("h2"), "foo.h2"); + + assertEquals("TheBody", myBean.body, "body"); + } + + @Override + protected Registry createRegistry() throws Exception { + Registry answer = super.createRegistry(); + answer.bind("myBean", myBean); + return answer; + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:in").to("bean:myBean?method=myMethod"); + } + }; + } + + public static class MyBean { + public Map<String, Object> variables; + public Object body; + + @Override + public String toString() { + return "MyBean[foo: " + variables + " body: " + body + "]"; + } + + public void myMethod(@Variables Map<String, Object> variables, Object body) { + this.variables = variables; + this.body = body; + LOG.info("myMethod() method called on {}", this); + } + + public void anotherMethod(@Variables Map<String, Object> variables, Object body) { + fail("Should not have called this method!"); + } + } +} diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/MethodFilterVariableTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/MethodFilterVariableTest.java new file mode 100644 index 00000000000..15a510d7c3a --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/processor/MethodFilterVariableTest.java @@ -0,0 +1,74 @@ +/* + * 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.ExchangePattern; +import org.apache.camel.Variable; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.spi.Registry; +import org.junit.jupiter.api.Test; + +public class MethodFilterVariableTest extends ContextTestSupport { + @Test + public void testSendMatchingMessage() throws Exception { + String body = "<person name='James' city='London'/>"; + getMockEndpoint("mock:result").expectedBodiesReceived(body); + + template.sendBodyAndHeader("direct:start", ExchangePattern.InOut, body, "city", "London"); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testSendNotMatchingMessage() throws Exception { + String body = "<person name='Hiram' city='Tampa'/>"; + getMockEndpoint("mock:result").expectedMessageCount(0); + + template.sendBodyAndHeader("direct:start", ExchangePattern.InOut, body, "city", "Tampa"); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + // START SNIPPET: example + from("direct:start") + .setVariable("location", header("city")) + .filter().method("myBean", "matches").to("mock:result"); + // END SNIPPET: example + } + }; + } + + @Override + protected Registry createRegistry() throws Exception { + Registry answer = super.createRegistry(); + answer.bind("myBean", new MyBean()); + return answer; + } + + // START SNIPPET: filter + public static class MyBean { + public boolean matches(@Variable("location") String location) { + return "London".equals(location); + } + } + // END SNIPPET: filter +} diff --git a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java index 820c42dfbce..2b00ee42e3b 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java @@ -178,6 +178,102 @@ public class ExpressionBuilder { }; } + /** + * Returns an expression for the variable with the given name + * + * @param variableName the name of the variable the expression will return + * @return an expression object which will return the variable value + */ + public static Expression variableExpression(final String variableName) { + return variableExpression(simpleExpression(variableName)); + } + + /** + * Returns an expression for the variable with the given name + * + * @param variableName the name of the variable the expression will return + * @return an expression object which will return the variable value + */ + public static Expression variableExpression(final Expression variableName) { + return new ExpressionAdapter() { + @Override + public Object evaluate(Exchange exchange) { + String name = variableName.evaluate(exchange, String.class); + return exchange.getVariable(name); + } + + @Override + public void init(CamelContext context) { + variableName.init(context); + } + + @Override + public String toString() { + return "variable(" + variableName + ")"; + } + }; + } + + /** + * Returns an expression for the variable with the given name converted to the given type + * + * @param variableName the name of the variable the expression will return + * @param type the type to convert to + * @return an expression object which will return the variable value + */ + public static <T> Expression variableExpression(final String variableName, final Class<T> type) { + return variableExpression(simpleExpression(variableName), constantExpression(type.getName())); + } + + /** + * Returns an expression for the variable with the given name converted to the given type + * + * @param variableName the name of the variable the expression will return + * @param typeName the type to convert to as a FQN class name + * @return an expression object which will return the header value + */ + public static Expression varibleExpression(final String variableName, final String typeName) { + return variableExpression(simpleExpression(variableName), simpleExpression(typeName)); + } + + /** + * Returns an expression for the variable with the given name converted to the given type + * + * @param variableName the name of the variable the expression will return + * @param typeName the type to convert to as a FQN class name + * @return an expression object which will return the header value + */ + public static Expression variableExpression(final Expression variableName, final Expression typeName) { + return new ExpressionAdapter() { + private ClassResolver classResolver; + + @Override + public Object evaluate(Exchange exchange) { + Class<?> type; + try { + String text = typeName.evaluate(exchange, String.class); + type = classResolver.resolveMandatoryClass(text); + } catch (ClassNotFoundException e) { + throw CamelExecutionException.wrapCamelExecutionException(exchange, e); + } + String text = variableName.evaluate(exchange, String.class); + return exchange.getVariable(text, type); + } + + @Override + public void init(CamelContext context) { + variableName.init(context); + typeName.init(context); + classResolver = context.getClassResolver(); + } + + @Override + public String toString() { + return "variableAs(" + variableName + ", " + typeName + ")"; + } + }; + } + /** * Returns an expression for the inbound message headers * @@ -197,6 +293,25 @@ public class ExpressionBuilder { }; } + /** + * Returns an expression for variables + * + * @return an expression object which will return the variables + */ + public static Expression variablesExpression() { + return new ExpressionAdapter() { + @Override + public Object evaluate(Exchange exchange) { + return exchange.getVariables(); + } + + @Override + public String toString() { + return "variables"; + } + }; + } + /** * Returns an expression for the exchange pattern * diff --git a/docs/user-manual/modules/ROOT/pages/parameter-binding-annotations.adoc b/docs/user-manual/modules/ROOT/pages/parameter-binding-annotations.adoc index 03861ef0ad2..6afb0d5a88c 100644 --- a/docs/user-manual/modules/ROOT/pages/parameter-binding-annotations.adoc +++ b/docs/user-manual/modules/ROOT/pages/parameter-binding-annotations.adoc @@ -9,11 +9,18 @@ The bean parameter binding annotations from Camel are as follows: |To bind to an inbound message body | |`org.apache.camel.Header` -|To bind to an message header |String name of the header +|To bind to a message header |String name of the header |`org.apache.camel.Headers` |To bind to the Map of the message headers | +|`org.apache.camel.Variable` +|To bind to a named variable |String name of the +variable + +|`org.apache.camel.Variables` +|To bind to the variables map | + |`org.apache.camel.ExchangeProperty` |To bind to a named property on the exchange |String name of the property
