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


Reply via email to