Author: davsclaus Date: Tue Feb 22 15:09:31 2011 New Revision: 1073359 URL: http://svn.apache.org/viewvc?rev=1073359&view=rev Log: CAMEL-3210: Property placeholders can now be used for any attribute in XML DSL. Using the xs:any for otherAttributes.
Added: camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertiesDslInvalidSyntaxTest.java camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertiesDslTest.java camel/trunk/components/camel-spring/src/test/java/org/apache/camel/component/properties/SpringOptionalPropertiesDslTest.java camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/SpringOptionalPropertiesDslTest.xml - copied, changed from r1073309, camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/SpringPropertiesComponent2Test.xml Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/model/Constants.java camel/trunk/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java camel/trunk/camel-core/src/test/resources/org/apache/camel/component/properties/myproperties.properties camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/myprop.properties Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/model/Constants.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/model/Constants.java?rev=1073359&r1=1073358&r2=1073359&view=diff ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/model/Constants.java (original) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/model/Constants.java Tue Feb 22 15:09:31 2011 @@ -31,6 +31,7 @@ public final class Constants { + "org.apache.camel.model.language:" + "org.apache.camel.model.loadbalancer"; + public static final String PLACEHOLDER_QNAME = "http://camel.apache.org/schema/placeholder"; private Constants() { } Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java?rev=1073359&r1=1073358&r2=1073359&view=diff ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java (original) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java Tue Feb 22 15:09:31 2011 @@ -19,7 +19,6 @@ package org.apache.camel.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; @@ -30,8 +29,10 @@ import java.util.concurrent.ExecutorServ import java.util.concurrent.TimeUnit; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAnyAttribute; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlTransient; +import javax.xml.namespace.QName; import org.apache.camel.Channel; import org.apache.camel.Endpoint; @@ -48,6 +49,7 @@ import org.apache.camel.builder.ErrorHan import org.apache.camel.builder.ExpressionBuilder; import org.apache.camel.builder.ExpressionClause; import org.apache.camel.builder.ProcessorBuilder; +import org.apache.camel.component.properties.PropertiesComponent; import org.apache.camel.model.language.ConstantExpression; import org.apache.camel.model.language.ExpressionDefinition; import org.apache.camel.model.language.LanguageExpression; @@ -89,6 +91,9 @@ public abstract class ProcessorDefinitio private ProcessorDefinition<?> parent; private final List<InterceptStrategy> interceptStrategies = new ArrayList<InterceptStrategy>(); + // use xs:any to support optional property placeholders + private Map<QName, Object> otherAttributes; + // else to use an optional attribute in JAXB2 public abstract List<ProcessorDefinition> getOutputs(); @@ -427,10 +432,34 @@ public abstract class ProcessorDefinitio log.trace("Resolving property placeholders for: " + definition); } - // find all String getter/setter + // find all getter/setter which we can use for property placeholders Map<Object, Object> properties = new HashMap<Object, Object>(); IntrospectionSupport.getProperties(definition, properties, null); + // include additional properties which have the Camel placeholder QName + // and when the definition parameter is this (otherAttributes belong to this) + if (definition.getOtherAttributes() != null) { + for (Object key : definition.getOtherAttributes().keySet()) { + QName qname = (QName) key; + if (Constants.PLACEHOLDER_QNAME.equals(qname.getNamespaceURI())) { + String local = qname.getLocalPart(); + Object value = definition.getOtherAttributes().get(key); + if (value != null && value instanceof String ) { + // value must be enclosed with placeholder tokens + String s = (String) value; + if (!s.startsWith(PropertiesComponent.PREFIX_TOKEN)) { + s = PropertiesComponent.PREFIX_TOKEN + s; + } + if (!s.endsWith(PropertiesComponent.SUFFIX_TOKEN)) { + s = s + PropertiesComponent.SUFFIX_TOKEN; + } + value = s; + } + properties.put(local, value); + } + } + } + if (!properties.isEmpty()) { if (log.isTraceEnabled()) { log.trace("There are " + properties.size() + " properties on: " + definition); @@ -442,12 +471,15 @@ public abstract class ProcessorDefinitio String name = (String) entry.getKey(); Object value = entry.getValue(); if (value instanceof String) { - // we can only resolve String typed values + // value must be a String, as a String is the key for a property placeholder String text = (String) value; text = routeContext.getCamelContext().resolvePropertyPlaceholders(text); if (text != value) { // invoke setter as the text has changed - IntrospectionSupport.setProperty(definition, name, text); + boolean changed = IntrospectionSupport.setProperty(routeContext.getCamelContext().getTypeConverter(), definition, name, text); + if (!changed) { + throw new IllegalArgumentException("No setter to set property: " + name + " to: " + text + " on: " + definition); + } if (log.isDebugEnabled()) { log.debug("Changed property [" + name + "] from: " + value + " to: " + text); } @@ -525,6 +557,35 @@ public abstract class ProcessorDefinitio // ------------------------------------------------------------------------- /** + * Adds a placeholder for the given option + * <p/> + * Requires using the {@link org.apache.camel.component.properties.PropertiesComponent} + * + * @param option the name of the option + * @param key the placeholder key + * @return the builder + */ + public Type placeholder(String option, String key) { + QName name = new QName(Constants.PLACEHOLDER_QNAME, option); + return attribute(name, key); + } + + /** + * Adds an optional attribute + * + * @param name the name of the attribute + * @param value the value + * @return the builder + */ + public Type attribute(QName name, Object value) { + if (otherAttributes == null) { + otherAttributes = new HashMap<QName, Object>(); + } + otherAttributes.put(name, value); + return (Type) this; + } + + /** * Sends the exchange to the given endpoint * * @param uri the endpoint to send to @@ -2922,6 +2983,15 @@ public abstract class ProcessorDefinitio this.inheritErrorHandler = inheritErrorHandler; } + public Map<QName, Object> getOtherAttributes() { + return otherAttributes; + } + + @XmlAnyAttribute + public void setOtherAttributes(Map<QName, Object> otherAttributes) { + this.otherAttributes = otherAttributes; + } + /** * Returns a label to describe this node such as the expression if some kind of expression node */ Added: camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertiesDslInvalidSyntaxTest.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertiesDslInvalidSyntaxTest.java?rev=1073359&view=auto ============================================================================== --- camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertiesDslInvalidSyntaxTest.java (added) +++ camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertiesDslInvalidSyntaxTest.java Tue Feb 22 15:09:31 2011 @@ -0,0 +1,77 @@ +/** + * 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.FailedToCreateRouteException; +import org.apache.camel.builder.RouteBuilder; + +/** + * Test that placeholder DSL is working as expected. + */ +public class OptionalPropertiesDslInvalidSyntaxTest extends ContextTestSupport { + + public void testPlaceholderDslKeyNotFoundTest() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .multicast().placeholder("stopOnException", "xxx") + .to("mock:a").throwException(new IllegalAccessException("Damn")).to("mock:b"); + } + }); + try { + context.start(); + fail("Should have thrown exception"); + } catch (FailedToCreateRouteException e) { + IllegalArgumentException cause = assertIsInstanceOf(IllegalArgumentException.class, e.getCause()); + assertEquals("Property with key [xxx] not found in properties for uri: {{xxx}}", cause.getMessage()); + } + } + + public void testPlaceholderDslSetterNotFoundTest() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .multicast().placeholder("xxx", "stop") + .to("mock:a").throwException(new IllegalAccessException("Damn")).to("mock:b"); + } + }); + try { + context.start(); + fail("Should have thrown exception"); + } catch (FailedToCreateRouteException e) { + IllegalArgumentException cause = assertIsInstanceOf(IllegalArgumentException.class, e.getCause()); + assertEquals("No setter to set property: xxx to: true on: Multicast[[To[mock:a], ThrowException[java.lang.IllegalAccessException], To[mock:b]]]", cause.getMessage()); + } + } + + @Override + public boolean isUseRouteBuilder() { + return false; + } + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + context.addComponent("properties", new PropertiesComponent("classpath:org/apache/camel/component/properties/myproperties.properties")); + return context; + } + +} Added: camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertiesDslTest.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertiesDslTest.java?rev=1073359&view=auto ============================================================================== --- camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertiesDslTest.java (added) +++ camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/OptionalPropertiesDslTest.java Tue Feb 22 15:09:31 2011 @@ -0,0 +1,65 @@ +/** + * 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; + +/** + * Test that placeholder DSL is working as expected. + */ +public class OptionalPropertiesDslTest extends ContextTestSupport { + + public void testPlaceholderDslTest() throws Exception { + getMockEndpoint("mock:a").expectedMessageCount(1); + getMockEndpoint("mock:b").expectedMessageCount(0); + + try { + template.sendBody("direct:start", "Hello World"); + fail("Should have thrown an exception"); + } catch (Exception e) { + // expected + } + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + // START SNIPPET: e1 + from("direct:start") + // use a property placeholder for the option stopOnException on the Multicast EIP + // which should have the value of {{stop}} key being looked up in the properties file + .multicast().placeholder("stopOnException", "stop") + .to("mock:a").throwException(new IllegalAccessException("Damn")).to("mock:b"); + // END SNIPPET: e1 + } + }; + } + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + context.addComponent("properties", new PropertiesComponent("classpath:org/apache/camel/component/properties/myproperties.properties")); + return context; + } + +} Modified: camel/trunk/camel-core/src/test/resources/org/apache/camel/component/properties/myproperties.properties URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/resources/org/apache/camel/component/properties/myproperties.properties?rev=1073359&r1=1073358&r2=1073359&view=diff ============================================================================== --- camel/trunk/camel-core/src/test/resources/org/apache/camel/component/properties/myproperties.properties (original) +++ camel/trunk/camel-core/src/test/resources/org/apache/camel/component/properties/myproperties.properties Tue Feb 22 15:09:31 2011 @@ -30,3 +30,5 @@ cool.mock=mock myCoolCharset=iso-8859-1 slipDelimiter=## + +stop=true \ No newline at end of file Added: camel/trunk/components/camel-spring/src/test/java/org/apache/camel/component/properties/SpringOptionalPropertiesDslTest.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-spring/src/test/java/org/apache/camel/component/properties/SpringOptionalPropertiesDslTest.java?rev=1073359&view=auto ============================================================================== --- camel/trunk/components/camel-spring/src/test/java/org/apache/camel/component/properties/SpringOptionalPropertiesDslTest.java (added) +++ camel/trunk/components/camel-spring/src/test/java/org/apache/camel/component/properties/SpringOptionalPropertiesDslTest.java Tue Feb 22 15:09:31 2011 @@ -0,0 +1,32 @@ +/** + * 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 static org.apache.camel.spring.processor.SpringTestHelper.createSpringCamelContext; + +/** + * Spring placeholder DSL test + */ +public class SpringOptionalPropertiesDslTest extends OptionalPropertiesDslTest { + + protected CamelContext createCamelContext() throws Exception { + return createSpringCamelContext(this, "org/apache/camel/component/properties/SpringOptionalPropertiesDslTest.xml"); + } + +} Copied: camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/SpringOptionalPropertiesDslTest.xml (from r1073309, camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/SpringPropertiesComponent2Test.xml) URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/SpringOptionalPropertiesDslTest.xml?p2=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/SpringOptionalPropertiesDslTest.xml&p1=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/SpringPropertiesComponent2Test.xml&r1=1073309&r2=1073359&rev=1073359&view=diff ============================================================================== --- camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/SpringPropertiesComponent2Test.xml (original) +++ camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/SpringOptionalPropertiesDslTest.xml Tue Feb 22 15:09:31 2011 @@ -15,38 +15,39 @@ See the License for the specific language governing permissions and limitations under the License. --> +<!-- START SNIPPET: e1 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:prop="http://camel.apache.org/schema/placeholder" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd "> + <!-- Notice in the declaration above, we have defined the prop prefix as the Camel placeholder namespace --> + + <bean id="damn" class="java.lang.IllegalArgumentException"> + <constructor-arg index="0" value="Damn"/> + </bean> + <camelContext xmlns="http://camel.apache.org/schema/spring"> <propertyPlaceholder id="properties" - location="classpath:org/apache/camel/component/properties/cheese.properties" + location="classpath:org/apache/camel/component/properties/myprop.properties" xmlns="http://camel.apache.org/schema/spring"/> <route> <from uri="direct:start"/> - <to uri="properties:{{cool.end}}"/> - </route> - - <route> - <from uri="direct:bar"/> - <to uri="properties:mock:{{cool.bar}}"/> + <!-- use prop namespace, to define a property placeholder, which maps to + option stopOnException={{stop}} --> + <multicast prop:stopOnException="stop"> + <to uri="mock:a"/> + <throwException ref="damn"/> + <to uri="mock:b"/> + </multicast> </route> - <route> - <from uri="direct:start2"/> - <to uri="{{cool.end}}"/> - </route> - - <route> - <from uri="direct:bar2"/> - <to uri="mock:{{cool.bar}}"/> - </route> </camelContext> </beans> +<!-- END SNIPPET: e1 --> Modified: camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/myprop.properties URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/myprop.properties?rev=1073359&r1=1073358&r2=1073359&view=diff ============================================================================== --- camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/myprop.properties (original) +++ camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/properties/myprop.properties Tue Feb 22 15:09:31 2011 @@ -20,4 +20,6 @@ routescan=component.properties.route routeincludes=*Simple* result=mock:result -mybuilder=simpleRoute \ No newline at end of file +mybuilder=simpleRoute + +stop=true \ No newline at end of file