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
commit cbc223bebf75f3afbef16040efe981865f6316bf Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Mon Mar 5 10:18:29 2018 +0100 CAMEL-12309: Support SpEL in non spring runtimes. Thanks to Jens Kleine-Herzbruch for the patch. --- .../camel-spring/src/main/docs/spel-language.adoc | 90 ++++++++++------------ .../apache/camel/language/spel/SpelExpression.java | 3 + .../camel/spring/util/RegistryBeanResolver.java | 50 ++++++++++++ .../camel/language/spel/SpelNonSpringTest.java | 59 ++++++++++++++ 4 files changed, 153 insertions(+), 49 deletions(-) diff --git a/components/camel-spring/src/main/docs/spel-language.adoc b/components/camel-spring/src/main/docs/spel-language.adoc index 0598556..f5c19f0 100644 --- a/components/camel-spring/src/main/docs/spel-language.adoc +++ b/components/camel-spring/src/main/docs/spel-language.adoc @@ -4,21 +4,21 @@ *Available as of Camel version 2.7* Camel allows -http://static.springsource.org/spring/docs/current/spring-framework-reference/htmlsingle/spring-framework-reference.html#expressions[SpEL] -to be used as an Expression or -Predicate in the DSL or -Xml Configuration. +https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#expressions[Spring Expression Language (SpEL)] +to be used as an Expression or Predicate in the DSL or XML Configuration. -### Variables +NOTE: It is recommended to use SpEL in Spring runtimes. However from Camel 2.21 onwards you can +use SpEL in other runtimes (there may be functionality SpEL cannot do when not running in a Spring runtime) -The following variables are available in expressions and predicates -written in SpEL: +=== Variables + +The following variables are available in expressions and predicates written in SpEL: [width="100%",cols="10%,10%,80%",options="header",] -|======================================================================= +|=== |Variable |Type |Description -|*this* |Exchange |the Exchange is the root object +|this |Exchange |the Exchange is the root object |exchange |Exchange |the Exchange object @@ -28,7 +28,7 @@ written in SpEL: |fault |Message |the Fault message (if any) -|body |Object |Camel 2.11: The IN message body. +|body |Object | The IN message body. |request |Message |the exchange.in message @@ -39,9 +39,9 @@ written in SpEL: |property(name) |Object |the property by the given name |property(name, type) |Type |the property by the given name as the given type -|======================================================================= +|=== -### Options +=== Options // language options: START The SpEL language supports 1 options which are listed below. @@ -55,9 +55,9 @@ The SpEL language supports 1 options which are listed below. |=== // language options: END -### Samples +=== Samples -#### Expression templating +==== Expression templating SpEL expressions need to be surrounded by `#{` `}` delimiters since expression templating is enabled. This allows you to combine SpEL @@ -67,9 +67,11 @@ template language. For example if you construct the following route: [source,java] ------------------------------------------------------------------------------------------------------------------------------------ -from("direct:example").setBody(spel("Hello #{request.body}! What a beautiful #{request.headers['dayOrNight']}")).to("mock:result"); ------------------------------------------------------------------------------------------------------------------------------------ +---- +from("direct:example") + .setBody(spel("Hello #{request.body}! What a beautiful #{request.headers['dayOrNight']}")) + .to("mock:result"); +---- In the route above, notice spel is a static method which we need to import from `org.apache.camel.language.spel.SpelExpression.spel`, as we @@ -78,9 +80,11 @@ to the `setBody` method. Though if we use the fluent API we can do this instead: [source,java] ------------------------------------------------------------------------------------------------------------------------------------- -from("direct:example").setBody().spel("Hello #{request.body}! What a beautiful #{request.headers['dayOrNight']}").to("mock:result"); ------------------------------------------------------------------------------------------------------------------------------------- +---- +from("direct:example") + .setBody().spel("Hello #{request.body}! What a beautiful #{request.headers['dayOrNight']}") + .to("mock:result"); +---- Notice we now use the `spel` method from the `setBody()` method. And this does not require us to static import the spel method from @@ -90,33 +94,33 @@ And sent a message with the string "World" in the body, and a header "dayOrNight" with value "day": [source,java] ---------------------------------------------------------------------------- +---- template.sendBodyAndHeader("direct:example", "World", "dayOrNight", "day"); ---------------------------------------------------------------------------- +---- The output on `mock:result` will be _"Hello World! What a beautiful day"_ -#### Bean integration +==== Bean integration You can reference beans defined in the Registry (most likely an `ApplicationContext`) in your SpEL expressions. For example if you have a bean named "foo" in your `ApplicationContext` you can invoke the "bar" method on this bean like this: -[source,java] --------------------- +[source,text] +---- #{@foo.bar == 'xyz'} --------------------- +---- -#### SpEL in enterprise integration patterns +==== SpEL in enterprise integration patterns You can use SpEL as an expression for link:recipient-list.html[Recipient List] or as a predicate inside a link:message-filter.html[Message Filter]: [source,xml] ---------------------------------------------------- +---- <route> <from uri="direct:foo"/> <filter> @@ -124,16 +128,18 @@ Filter]: <to uri="direct:bar"/> </filter> </route> ---------------------------------------------------- +---- And the equivalent in Java DSL: [source,java] -------------------------------------------------------------------------------------------- - from("direct:foo").filter().spel("#{request.headers['foo'] == 'bar'}").to("direct:bar"); -------------------------------------------------------------------------------------------- +---- +from("direct:foo") + .filter().spel("#{request.headers['foo'] == 'bar'}") + .to("direct:bar"); +---- -### Loading script from external resource +=== Loading script from external resource *Available as of Camel 2.11* @@ -143,21 +149,7 @@ such as `"classpath:"`, `"file:"`, or `"http:"`. + eg to refer to a file on the classpath you can do: [source,java] ------------------------------------------------------------- +---- .setHeader("myHeader").spel("resource:classpath:myspel.txt") ------------------------------------------------------------- +---- -### Dependencies - -You need Spring 3.0 or higher to use Spring Expression Language. If you -use Maven you could just add the following to your `pom.xml`: - -[source,xml] ----------------------------------------------------------- -<dependency> - <groupId>org.apache.camel</groupId> - <artifactId>camel-spring</artifactId> - <version>xxx</version> - <!-- use the same version as your Camel core version --> -</dependency> ----------------------------------------------------------- \ No newline at end of file diff --git a/components/camel-spring/src/main/java/org/apache/camel/language/spel/SpelExpression.java b/components/camel-spring/src/main/java/org/apache/camel/language/spel/SpelExpression.java index 7c7642a..e410e1d 100644 --- a/components/camel-spring/src/main/java/org/apache/camel/language/spel/SpelExpression.java +++ b/components/camel-spring/src/main/java/org/apache/camel/language/spel/SpelExpression.java @@ -20,6 +20,7 @@ import org.apache.camel.Exchange; import org.apache.camel.ExpressionEvaluationException; import org.apache.camel.impl.ExpressionSupport; import org.apache.camel.spring.SpringCamelContext; +import org.apache.camel.spring.util.RegistryBeanResolver; import org.springframework.context.ApplicationContext; import org.springframework.context.expression.BeanFactoryResolver; import org.springframework.expression.EvaluationContext; @@ -71,6 +72,8 @@ public class SpelExpression extends ExpressionSupport { // Support references (like @foo) in expressions to beans defined in the Registry/ApplicationContext ApplicationContext applicationContext = ((SpringCamelContext) exchange.getContext()).getApplicationContext(); evaluationContext.setBeanResolver(new BeanFactoryResolver(applicationContext)); + } else { + evaluationContext.setBeanResolver(new RegistryBeanResolver(exchange.getContext().getRegistry())); } return evaluationContext; } diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/util/RegistryBeanResolver.java b/components/camel-spring/src/main/java/org/apache/camel/spring/util/RegistryBeanResolver.java new file mode 100644 index 0000000..63b45d8 --- /dev/null +++ b/components/camel-spring/src/main/java/org/apache/camel/spring/util/RegistryBeanResolver.java @@ -0,0 +1,50 @@ +/** + * 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.spring.util; + +import org.apache.camel.NoSuchBeanException; +import org.apache.camel.spi.Registry; +import org.springframework.expression.AccessException; +import org.springframework.expression.BeanResolver; +import org.springframework.expression.EvaluationContext; + +/** + * EL bean resolver that operates against a Camel {@link Registry}. + */ +public final class RegistryBeanResolver implements BeanResolver { + + private final Registry registry; + + public RegistryBeanResolver(Registry registry) { + this.registry = registry; + } + + @Override + public Object resolve(EvaluationContext context, String beanName) throws AccessException { + Object bean = null; + try { + bean = registry.lookupByName(beanName); + } catch (NoSuchBeanException e) { + // ignore + } + if (bean == null) { + throw new AccessException("Could not resolve bean reference against Registry"); + } + return bean; + } + +} diff --git a/components/camel-spring/src/test/java/org/apache/camel/language/spel/SpelNonSpringTest.java b/components/camel-spring/src/test/java/org/apache/camel/language/spel/SpelNonSpringTest.java new file mode 100644 index 0000000..2122f26 --- /dev/null +++ b/components/camel-spring/src/test/java/org/apache/camel/language/spel/SpelNonSpringTest.java @@ -0,0 +1,59 @@ +/** + * 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.language.spel; + +import org.apache.camel.CamelContext; +import org.apache.camel.ExpressionEvaluationException; +import org.apache.camel.LanguageTestSupport; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.impl.SimpleRegistry; +import org.apache.camel.language.spel.bean.Dummy; + +/** + * Test access to beans defined in non-Spring context from SpEL expressions/predicates. + */ +public class SpelNonSpringTest extends LanguageTestSupport { + + @Override + protected CamelContext createCamelContext() throws Exception { + SimpleRegistry registry = new SimpleRegistry(); + registry.put("myDummy", new Dummy()); + return new DefaultCamelContext(registry); + } + + public void testSpelBeanExpressions() throws Exception { + assertExpression("#{@myDummy.foo == 'xyz'}", true); + assertExpression("#{@myDummy.bar == 789}", true); + assertExpression("#{@myDummy.bar.toString()}", "789"); + try { + assertExpression("#{@notFound}", null); + } catch (ExpressionEvaluationException ex) { + assertStringContains(ex.getMessage(), "Could not resolve bean reference against Registry"); + } + } + + public void testSpelBeanPredicates() throws Exception { + assertPredicate("@myDummy.foo == 'xyz'"); + assertPredicate("@myDummy.bar == 789"); + assertPredicate("@myDummy.bar instanceof T(Integer)"); + } + + @Override + protected String getLanguageName() { + return "spel"; + } +} -- To stop receiving notification emails like this one, please contact davscl...@apache.org.