This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch CAMEL-13947 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 106a6e451f1d70640018800d30b1c53dec6a0cd3 Author: Claus Ibsen <[email protected]> AuthorDate: Wed Sep 25 19:46:05 2019 +0200 CAMEL-13947: PropertiesComponent should be a static service and resolved like other similar features. --- core/camel-base/src/main/docs/simple-language.adoc | 13 ++++ .../simple/ast/SimpleFunctionExpression.java | 15 +++++ .../camel/builder/xml/XPathFunctionsTest.java | 2 +- ...opertiesComponentConcatenatePropertiesTest.java | 4 +- .../PropertiesComponentEIPChoiceSimpleTest.java | 2 +- .../PropertiesComponentEndpointMandatoryTest.java | 50 ---------------- .../PropertiesComponentNestPropertiesTest.java | 70 ---------------------- .../PropertiesComponentSimpleLanguageTest.java | 66 -------------------- .../camel/impl/MultipleLifecycleStrategyTest.java | 2 +- .../camel/support/builder/ExpressionBuilder.java | 24 ++++++++ 10 files changed, 57 insertions(+), 191 deletions(-) diff --git a/core/camel-base/src/main/docs/simple-language.adoc b/core/camel-base/src/main/docs/simple-language.adoc index 5fc83b4..0c6e3c0 100644 --- a/core/camel-base/src/main/docs/simple-language.adoc +++ b/core/camel-base/src/main/docs/simple-language.adoc @@ -179,6 +179,10 @@ Specifying a method name you must use dot as separator. We also support the ?method=methodname syntax that is used by the xref:components::bean-component.adoc[Bean] component. +|`properties:key:default` |String |Lookup a property with the given key. If the key does +not exists or has no value, then an optional default value can be +specified. + |routeId |String |Returns the id of the current route the Exchange is being routed. @@ -775,6 +779,15 @@ a `java.util.Map` and we then lookup with the key `gold` and return the value. If the header is not convertible to Map an exception is thrown. If the header with name `type` does not exist `null` is returned. +You can nest functions, such as shown below: + +[source,xml] +---- +<setHeader name="myHeader"> + <simple>${properties:${header.someKey}}</simple> +</setHeader> +---- + == Referring to constants or enums Suppose you have an enum for customers diff --git a/core/camel-base/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java b/core/camel-base/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java index d6eab1f..adabcdc 100644 --- a/core/camel-base/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java +++ b/core/camel-base/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java @@ -208,6 +208,21 @@ public class SimpleFunctionExpression extends LiteralExpression { return ExpressionBuilder.beanExpression(remainder); } + // properties: prefix + remainder = ifStartsWithReturnRemainder("properties:", function); + if (remainder != null) { + String[] parts = remainder.split(":"); + if (parts.length > 2) { + throw new SimpleParserException("Valid syntax: ${properties:key[:default]} was: " + function, token.getIndex()); + } + String defaultValue = null; + if (parts.length >= 2) { + defaultValue = parts[1]; + } + String key = parts[0]; + return ExpressionBuilder.propertiesComponentExpression(key, defaultValue); + } + // ref: prefix remainder = ifStartsWithReturnRemainder("ref:", function); if (remainder != null) { diff --git a/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsTest.java b/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsTest.java index b6d3acc..6335b3a 100644 --- a/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/builder/xml/XPathFunctionsTest.java @@ -79,7 +79,7 @@ public class XPathFunctionsTest extends ContextTestSupport { // here we use the simple language to evaluate the // expression // which at runtime will be evaluated to 'Donkey Kong' - .when().xpath("//name = function:simple('Donkey ${properties:bar}')").to("mock:donkey").otherwise().to("mock:other").end(); + .when().xpath("//name = function:simple('Donkey {{bar}}')").to("mock:donkey").otherwise().to("mock:other").end(); // END SNIPPET: ex } }; diff --git a/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentConcatenatePropertiesTest.java b/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentConcatenatePropertiesTest.java index 85adbe3..02f6b09 100644 --- a/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentConcatenatePropertiesTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentConcatenatePropertiesTest.java @@ -50,7 +50,7 @@ public class PropertiesComponentConcatenatePropertiesTest extends ContextTestSup context.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { - from("direct:start").setBody(simple("${properties:concat.property}")).to("mock:result"); + from("direct:start").setBody(simple("{{concat.property}}")).to("mock:result"); } }); context.start(); @@ -67,7 +67,7 @@ public class PropertiesComponentConcatenatePropertiesTest extends ContextTestSup context.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { - from("direct:start").setBody(simple("${properties:property.complete}")).to("mock:result"); + from("direct:start").setBody(simple("{{property.complete}}")).to("mock:result"); } }); context.start(); diff --git a/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentEIPChoiceSimpleTest.java b/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentEIPChoiceSimpleTest.java index f1b0294..f16f3d8 100644 --- a/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentEIPChoiceSimpleTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentEIPChoiceSimpleTest.java @@ -40,7 +40,7 @@ public class PropertiesComponentEIPChoiceSimpleTest extends ContextTestSupport { return new RouteBuilder() { @Override public void configure() throws Exception { - from("direct:start").choice().when(simple("${body} contains '${properties:cool.name}'")).to("mock:camel").otherwise().to("mock:other"); + from("direct:start").choice().when(simple("${body} contains '{{cool.name}}'")).to("mock:camel").otherwise().to("mock:other"); } }; } diff --git a/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentEndpointMandatoryTest.java b/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentEndpointMandatoryTest.java deleted file mode 100644 index aa77624..0000000 --- a/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentEndpointMandatoryTest.java +++ /dev/null @@ -1,50 +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.component.properties; - -import org.apache.camel.ContextTestSupport; -import org.apache.camel.RuntimeCamelException; -import org.apache.camel.builder.RouteBuilder; -import org.junit.Test; - -public class PropertiesComponentEndpointMandatoryTest extends ContextTestSupport { - - @Override - public boolean isUseRouteBuilder() { - return false; - } - - @Test - public void testPropertiesComponentMandatory() throws Exception { - context.removeComponent("properties"); - try { - context.addRoutes(new RouteBuilder() { - @Override - public void configure() throws Exception { - from("{{cool.start}}").to("log:{{cool.start}}?showBodyType=false&showExchangeId={{cool.showid}}").to("mock:{{cool.result}}"); - } - }); - context.start(); - fail("Should throw exception"); - } catch (RuntimeCamelException e) { - IllegalArgumentException cause = assertIsInstanceOf(IllegalArgumentException.class, e.getCause()); - String msg = "PropertiesComponent with name properties must be defined in CamelContext to support property placeholders."; - assertTrue(cause.getMessage().startsWith(msg)); - } - } - -} diff --git a/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentNestPropertiesTest.java b/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentNestPropertiesTest.java deleted file mode 100644 index 298e59f..0000000 --- a/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentNestPropertiesTest.java +++ /dev/null @@ -1,70 +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.component.properties; - -import org.apache.camel.CamelContext; -import org.apache.camel.ContextTestSupport; -import org.apache.camel.builder.RouteBuilder; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class PropertiesComponentNestPropertiesTest extends ContextTestSupport { - - @Override - protected CamelContext createCamelContext() throws Exception { - CamelContext context = super.createCamelContext(); - context.getPropertiesComponent().setLocation("classpath:org/apache/camel/component/properties/adapter.properties"); - return context; - } - - @Override - @Before - public void setUp() throws Exception { - System.setProperty("environment", "junit"); - super.setUp(); - } - - @Override - @After - public void tearDown() throws Exception { - System.clearProperty("environment"); - super.tearDown(); - } - - @Test - public void testPropertiesComponentDefault() throws Exception { - context.addRoutes(new RouteBuilder() { - @Override - public void configure() throws Exception { - from("direct:start").setBody(simple("${properties:someproperty}${body}")).to("mock:result"); - - from("direct:start2").setBody(simple("{json:{value:${properties:someproperty}}}")).to("mock:result2"); - } - }); - context.start(); - - getMockEndpoint("mock:result").expectedBodiesReceived("junitTest"); - getMockEndpoint("mock:result2").expectedBodiesReceived("{json:{value:junit}}"); - - template.sendBody("direct:start", "Test"); - template.sendBody("direct:start2", "Test"); - - assertMockEndpointsSatisfied(); - } - -} diff --git a/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentSimpleLanguageTest.java b/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentSimpleLanguageTest.java deleted file mode 100644 index d12d7ad..0000000 --- a/core/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentSimpleLanguageTest.java +++ /dev/null @@ -1,66 +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.component.properties; - -import org.apache.camel.CamelContext; -import org.apache.camel.ContextTestSupport; -import org.apache.camel.builder.RouteBuilder; -import org.junit.Test; - -public class PropertiesComponentSimpleLanguageTest extends ContextTestSupport { - - @Override - public boolean isUseRouteBuilder() { - return false; - } - - @Test - public void testPropertiesComponentSimpleLanguage() throws Exception { - context.addRoutes(new RouteBuilder() { - @Override - public void configure() throws Exception { - from("direct:start").transform().simple("Hi ${body} do you think ${properties:cheese.quote}?"); - } - }); - context.start(); - - String reply = template.requestBody("direct:start", "Claus", String.class); - assertEquals("Hi Claus do you think Camel rocks?", reply); - } - - @Test - public void testPropertiesComponentDualSimpleLanguage() throws Exception { - context.addRoutes(new RouteBuilder() { - @Override - public void configure() throws Exception { - from("direct:start").transform().simple("Hi ${body} do you think ${properties:cheese.quote}? And do you like ${properties:cheese.type} cheese?"); - } - }); - context.start(); - - String reply = template.requestBody("direct:start", "Claus", String.class); - assertEquals("Hi Claus do you think Camel rocks? And do you like Gouda cheese?", reply); - } - - @Override - protected CamelContext createCamelContext() throws Exception { - CamelContext context = super.createCamelContext(); - context.getPropertiesComponent().setLocation("classpath:org/apache/camel/component/properties/cheese.properties"); - return context; - } - -} diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/MultipleLifecycleStrategyTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/MultipleLifecycleStrategyTest.java index 851cdf8..7e503d3 100644 --- a/core/camel-core/src/test/java/org/apache/camel/impl/MultipleLifecycleStrategyTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/impl/MultipleLifecycleStrategyTest.java @@ -52,7 +52,7 @@ public class MultipleLifecycleStrategyTest extends TestSupport { List<String> expectedEvents = Arrays.asList("onContextStart", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", "onServiceAdd", - "onServiceAdd", "onServiceAdd", "onComponentAdd", "onEndpointAdd", "onComponentRemove", "onContextStop"); + "onServiceAdd", "onServiceAdd", "onServiceAdd", "onComponentAdd", "onEndpointAdd", "onComponentRemove", "onContextStop"); assertEquals(expectedEvents, dummy1.getEvents()); assertEquals(expectedEvents, dummy2.getEvents()); 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 6efc2e9..48bdd26 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 @@ -1310,6 +1310,30 @@ public class ExpressionBuilder { return constantExpression(str); } + public static Expression propertiesComponentExpression(final String key, final String defaultValue) { + return new ExpressionAdapter() { + public Object evaluate(Exchange exchange) { + String text = simpleExpression(key).evaluate(exchange, String.class); + try { + PropertiesComponent pc = exchange.getContext().getPropertiesComponent(); + // enclose key with {{ }} to force parsing as key can be a nested expression too + return pc.parseUri(PropertiesComponent.PREFIX_TOKEN + text + PropertiesComponent.SUFFIX_TOKEN); + } catch (Exception e) { + // property with key not found, use default value if provided + if (defaultValue != null) { + return defaultValue; + } + throw RuntimeCamelException.wrapRuntimeCamelException(e); + } + } + + @Override + public String toString() { + return "properties(" + key + ")"; + } + }; + } + /** * Returns an {@link TokenPairExpressionIterator} expression */
