You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by js...@apache.org on 2013/04/23 10:00:09 UTC

svn commit: r1470840 - in /camel/trunk/camel-core/src: main/java/org/apache/camel/ main/java/org/apache/camel/component/seda/ main/java/org/apache/camel/impl/ test/java/org/apache/camel/impl/

Author: jstrachan
Date: Tue Apr 23 08:00:07 2013
New Revision: 1470840

URL: http://svn.apache.org/r1470840
Log:
Initial implementation of CAMEL-6306 to add a ComponentConfiguration API on Component; which is like EndpointConfiguration but can be created on a Component and used to create (or edit) an Endpoint or a URI string. Also adds a UriEndpointComponent which is a handy base class for any endpoint which is annotated by @UriEndpoint so that it can return better metadata in its ComponentConfiguration implementation

Added:
    camel/trunk/camel-core/src/main/java/org/apache/camel/ComponentConfiguration.java
      - copied, changed from r1468302, camel/trunk/camel-core/src/main/java/org/apache/camel/EndpointConfiguration.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/InvalidPropertyException.java   (with props)
    camel/trunk/camel-core/src/main/java/org/apache/camel/impl/AnnotatedParameterConfiguration.java   (with props)
    camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ComponentConfigurationSupport.java   (with props)
    camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultComponentConfiguration.java   (with props)
    camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ParameterConfiguration.java   (with props)
    camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriComponentConfiguration.java   (with props)
    camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriEndpointComponent.java   (with props)
    camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriEndpointConfiguration.java   (with props)
    camel/trunk/camel-core/src/test/java/org/apache/camel/impl/ComponentConfigurationTest.java   (with props)
Modified:
    camel/trunk/camel-core/src/main/java/org/apache/camel/Component.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/component/seda/SedaComponent.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultComponent.java
    camel/trunk/camel-core/src/test/java/org/apache/camel/impl/ConfigurationHelperTest.java
    camel/trunk/camel-core/src/test/java/org/apache/camel/impl/EndpointConfigurationTest.java

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/Component.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/Component.java?rev=1470840&r1=1470839&r2=1470840&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/Component.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/Component.java Tue Apr 23 08:00:07 2013
@@ -60,4 +60,15 @@ public interface Component extends Camel
      * @since Camel 2.9.0
      */
     EndpointConfiguration createConfiguration(String uri) throws Exception;
+
+    /**
+     * Creates a configuration helper object for a component that lets you configure the various
+     * URI and parameter values; then create the full URI for it, create a new Endpoint from it
+     * or configure an existing Endpoint from the values.
+     *
+     * This method is intended to be used in cases where there is not yet a full URI to
+     * configure an endpoint yet; but rather there are a number of parameters to configure
+     * to then build up a new URI or directly create an Endpoint from the parameter values.
+     */
+    ComponentConfiguration createComponentConfiguration();
 }

Copied: camel/trunk/camel-core/src/main/java/org/apache/camel/ComponentConfiguration.java (from r1468302, camel/trunk/camel-core/src/main/java/org/apache/camel/EndpointConfiguration.java)
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/ComponentConfiguration.java?p2=camel/trunk/camel-core/src/main/java/org/apache/camel/ComponentConfiguration.java&p1=camel/trunk/camel-core/src/main/java/org/apache/camel/EndpointConfiguration.java&r1=1468302&r2=1470840&rev=1470840&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/EndpointConfiguration.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/ComponentConfiguration.java Tue Apr 23 08:00:07 2013
@@ -16,61 +16,126 @@
  */
 package org.apache.camel;
 
-import java.net.URI;
+import org.apache.camel.impl.ParameterConfiguration;
+
+import java.net.URISyntaxException;
+import java.util.Map;
+import java.util.SortedMap;
 
 /**
- * Holds an {@link Endpoint} configuration as a pojo that can be manipulated and validated.
- * Camel endpoint configuration is strongly related to URIs.
+ * Represents a set of configuration values for an endpoint URI which can be created from a URI string
+ * or a base URI string and a set of parameter names and values.
+ *
+ * The configuration values can then be introspected, modified and converted back into a URI string
+ * or Endpoint.
+ *
+ * For @{link UriEndpointComponent} implementations created for Endpoints annotated with {@link UriEndpoint} and the
+ * associated annotations then all the parameter values can be introspected and the parameter values are converted to their
+ * correct type.
+ *
+ * Other implementations keep all the types as String and there is no validation until you try to create
+ * an Endpoint from the values.
  */
-public interface EndpointConfiguration {
+public interface ComponentConfiguration {
 
-    String URI_SCHEME               = "scheme";
-    String URI_SCHEME_SPECIFIC_PART = "schemeSpecificPart";
-    String URI_AUTHORITY            = "authority";
-    String URI_USER_INFO            = "userInfo";
-    String URI_HOST                 = "host";
-    String URI_PORT                 = "port";
-    String URI_PATH                 = "path";
-    String URI_QUERY                = "query";
-    String URI_FRAGMENT             = "fragment";
+    /**
+     * Returns the base URI without any query parameters added
+     */
+    String getBaseUri();
+
+    /**
+     * Sets the base URI without any query parameters added
+     */
+    void setBaseUri(String baseUri);
+
+
+    /**
+     * Returns the current parameters of the configuration (usually encoded as ?foo=bar&whatnot=something URI query parameters)
+     */
+    Map<String, Object> getParameters();
 
     /**
-     * {@link org.apache.camel.spi.DataFormat} operations.
+     * Sets the parameter values of this configuration
      */
-    public enum UriFormat {
-        Canonical, Provider, Consumer, Complete
-    }
+    void setParameters(Map<String, Object> propertyValues);
 
     /**
-     * Returns the URI configuration of an {@link Endpoint}.
+     * Returns the parameter value for the given name
      *
-     * @return the configuration URI.
+     * @param name the name of the URI query parameter to get
+     * @return the value of the parameter
      */
-    URI getURI();
+    Object getParameter(String name);
 
     /**
-     * Gets the value of a particular parameter.
+     * Sets the parameter value of the given name
      *
-     * @param name the parameter name
-     * @return the configuration URI.
-     * @throws RuntimeCamelException is thrown if error getting the parameter
+     * @param name  the name of the URI query parameter
+     * @param value the new value of the parameter
+     */
+    void setParameter(String name, Object value);
+
+
+    /**
+     * Returns the URI string (without schema) with query parameters for the current
+     * configuration which can then be used to create an {@link org.apache.camel.Endpoint}
      */
-    <T> T getParameter(String name) throws RuntimeCamelException;
+    String getUriString();
 
     /**
-     * Sets the value of a particular parameter.
+     * Sets the URI string (without schema but with optional query parameters)
+     * which will update the {@link #getBaseUri()} and the {@link #getParameters()} values
      *
-     * @param name  the parameter name
-     * @param value the parameter value
-     * @throws RuntimeCamelException is thrown if error setting the parameter
+     * @param newValue the new URI string with query arguments
      */
-    <T> void setParameter(String name, T value) throws RuntimeCamelException;
+    void setUriString(String newValue) throws URISyntaxException;
 
     /**
-     * Returns the formatted configuration string of an {@link Endpoint}.
+     * Returns the URI query parameter configuration for the given parameter name or null if it does not exist
+     */
+    ParameterConfiguration getParameterConfiguration(String name);
+
+    /**
+     * Returns the sorted map of all the parameter names to their {@link ParameterConfiguration} objects
+     */
+    SortedMap<String, ParameterConfiguration> getParameterConfigurationMap();
+
+
+    /**
+     * Converts the configuration into a URI and then looks up the endpoint in the {@link CamelContext}
+     * which typically results in a new {@link Endpoint} instance being creatd.
+     */
+    Endpoint createEndpoint() throws Exception;
+
+    /**
+     * Applies the current set of parameters to the given endpoint instance.
+     * <p/>
+     * Note that typically parts of the URI are not injected into the Endpoint; this method purely
      *
-     * @param format the format
-     * @return the configuration URI in String format.
+     * @param endpoint
      */
-    String toUriString(UriFormat format);
+    void configureEndpoint(Endpoint endpoint);
+
+
+    /**
+     * Gets the named URI parameter value on the given endpoint
+     *
+     * @param endpoint the endpoint instance
+     * @param name     the name of the URI query parameter
+     * @return the value of the parameter
+     * @throws RuntimeCamelException if the parameter name does not exist on the endpoint
+     */
+    Object getEndpointParameter(Endpoint endpoint, String name) throws RuntimeCamelException;
+
+    /**
+     * Sets the named URI query parameter value on the given endpoint
+     *
+     * @param endpoint the endpoint instance
+     * @param name     the name of the URI query parameter
+     * @param value    the new value of the URI query parameter
+     * @throws RuntimeCamelException
+     */
+    void setEndpointParameter(Endpoint endpoint, String name, Object value) throws RuntimeCamelException;
+
 }
+

Added: camel/trunk/camel-core/src/main/java/org/apache/camel/InvalidPropertyException.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/InvalidPropertyException.java?rev=1470840&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/InvalidPropertyException.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/InvalidPropertyException.java Tue Apr 23 08:00:07 2013
@@ -0,0 +1,44 @@
+/**
+ * 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;
+
+/**
+ * An exception caused when an invalid property name is used on an object
+ */
+public class InvalidPropertyException extends RuntimeCamelException {
+    private static final long serialVersionUID = 3450859794325167954L;
+    private final transient Object owner;
+    private final String propertyName;
+
+    public InvalidPropertyException(Object owner, String propertyName) {
+        this(owner, propertyName, owner != null ? owner.getClass() : Object.class);
+    }
+
+    public InvalidPropertyException(Object owner, String propertyName, Class<?> type) {
+        super("No '" + propertyName + "' property available on type: " + type.getName() + " in: " + owner);
+        this.owner = owner;
+        this.propertyName = propertyName;
+    }
+
+    public String getPropertyName() {
+        return propertyName;
+    }
+
+    public Object getOwner() {
+        return owner;
+    }
+}

Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/InvalidPropertyException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/seda/SedaComponent.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/seda/SedaComponent.java?rev=1470840&r1=1470839&r2=1470840&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/component/seda/SedaComponent.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/seda/SedaComponent.java Tue Apr 23 08:00:07 2013
@@ -24,6 +24,7 @@ import java.util.concurrent.LinkedBlocki
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
 import org.apache.camel.impl.DefaultComponent;
+import org.apache.camel.impl.UriEndpointComponent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,13 +34,17 @@ import org.slf4j.LoggerFactory;
  *
  * @version 
  */
-public class SedaComponent extends DefaultComponent {
+public class SedaComponent extends UriEndpointComponent {
     protected final transient Logger log = LoggerFactory.getLogger(getClass());
     protected final int maxConcurrentConsumers = 500;
     protected int queueSize;
     protected int defaultConcurrentConsumers = 1;
     private final Map<String, QueueReference> queues = new HashMap<String, QueueReference>();
-    
+
+    public SedaComponent() {
+        super(SedaEndpoint.class);
+    }
+
     public void setQueueSize(int size) {
         queueSize = size;
     }

Added: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/AnnotatedParameterConfiguration.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/AnnotatedParameterConfiguration.java?rev=1470840&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/AnnotatedParameterConfiguration.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/AnnotatedParameterConfiguration.java Tue Apr 23 08:00:07 2013
@@ -0,0 +1,43 @@
+/**
+ *
+ * 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.impl;
+
+import java.lang.reflect.AccessibleObject;
+
+/**
+ * An implementation of {@link ParameterConfiguration} which comes from a field or setter method
+ * which has access to its underlying annotations to be able to expose additional validation
+ * and conversion metadata for the parameter via annotations
+ */
+public class AnnotatedParameterConfiguration extends ParameterConfiguration {
+    private final AccessibleObject accessibleObject;
+
+    public AnnotatedParameterConfiguration(String name, Class<?> type, AccessibleObject accessibleObject) {
+        super(name, type);
+        this.accessibleObject = accessibleObject;
+    }
+
+    public AccessibleObject getAccessibleObject() {
+        return accessibleObject;
+    }
+
+    @Override
+    public String toString() {
+        return "AnnotatedParameterConfiguration[" + getName() + " on " + accessibleObject + "]";
+    }
+}

Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/AnnotatedParameterConfiguration.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ComponentConfigurationSupport.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ComponentConfigurationSupport.java?rev=1470840&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ComponentConfigurationSupport.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ComponentConfigurationSupport.java Tue Apr 23 08:00:07 2013
@@ -0,0 +1,176 @@
+/**
+ *
+ * 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.impl;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.Component;
+import org.apache.camel.ComponentConfiguration;
+import org.apache.camel.Endpoint;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.URISupport;
+import org.apache.camel.util.UnsafeUriCharactersEncoder;
+
+/**
+ * Useful base class for implementations of {@link ComponentConfiguration}
+ */
+public abstract class ComponentConfigurationSupport implements ComponentConfiguration {
+    protected final Component component;
+    private Map<String, Object> propertyValues = new HashMap<String, Object>();
+    private String baseUri;
+
+    public ComponentConfigurationSupport(Component component) {
+        this.component = component;
+    }
+
+    @Override
+    public Map<String, Object> getParameters() {
+        return Collections.unmodifiableMap(propertyValues);
+    }
+
+    @Override
+    public void setParameters(Map<String, Object> newValues) {
+        ObjectHelper.notNull(newValues, "propertyValues");
+        this.propertyValues.clear();
+        // lets validate each property as we set it
+        Set<Map.Entry<String, Object>> entries = newValues.entrySet();
+        for (Map.Entry<String, Object> entry : entries) {
+            setParameter(entry.getKey(), entry.getValue());
+        }
+    }
+
+    @Override
+    public Object getParameter(String name) {
+        validatePropertyName(name);
+        return propertyValues.get(name);
+    }
+
+    @Override
+    public void setParameter(String name, Object value) {
+        Object convertedValue = validatePropertyValue(name, value);
+        propertyValues.put(name, convertedValue);
+    }
+
+    /**
+     * Returns the base URI without any scheme or URI query parameters (property values)
+     */
+    @Override
+    public String getBaseUri() {
+        return baseUri;
+    }
+
+    @Override
+    public void setBaseUri(String baseUri) {
+        this.baseUri = baseUri;
+    }
+
+    @Override
+    public Endpoint createEndpoint() throws Exception {
+        String uri = getUriString();
+        return component.createEndpoint(uri);
+    }
+
+    /**
+     * Configures the properties on the given endpoint
+     */
+    @Override
+    public void configureEndpoint(Endpoint endpoint) {
+        Map<String, Object> map = getParameters();
+        if (map != null) {
+            Set<Map.Entry<String, Object>> entries = map.entrySet();
+            for (Map.Entry<String, Object> entry : entries) {
+                setEndpointParameter(endpoint, entry.getKey(), entry.getValue());
+            }
+        }
+        // TODO validate all the values are valid (e.g. mandatory)
+    }
+
+    @Override
+    public String getUriString() {
+        List<String> queryParams = new ArrayList<String>();
+        for (Map.Entry<String, Object> entry : getParameters().entrySet()) {
+            String key = entry.getKey();
+            Object value = entry.getValue();
+            // convert to "param=value" format here, order will be preserved
+            if (value instanceof List) {
+                for (Object item : (List<?>)value) {
+                    queryParams.add(key + "=" + UnsafeUriCharactersEncoder.encode(item.toString()));
+                }
+            } else {
+                queryParams.add(key + "=" + UnsafeUriCharactersEncoder.encode(value.toString()));
+            }
+        }
+        Collections.sort(queryParams);
+        StringBuilder builder = new StringBuilder();
+        String base = getBaseUri();
+        if (base != null) {
+            builder.append(base);
+        }
+        String separator = "?";
+        for (String entry : queryParams) {
+            builder.append(separator);
+            builder.append(entry);
+            separator = "&";
+        }
+        return builder.toString();
+    }
+
+    @Override
+    public void setUriString(String uri) throws URISyntaxException {
+        String path = uri;
+        int idx = path.indexOf('?');
+        Map<String, Object> newParameters = Collections.EMPTY_MAP;
+        if (idx >= 0) {
+            path = path.substring(0, idx);
+            String query = uri.substring(idx + 1);
+            newParameters = URISupport.parseQuery(query, true);
+        }
+        setBaseUri(path);
+        setParameters(newParameters);
+    }
+
+    @Override
+    public ParameterConfiguration getParameterConfiguration(String name) {
+        return getParameterConfigurationMap().get(name);
+    }
+
+    /**
+     * Allow implementations to validate whether a property name is valid
+     * and either throw an exception or log a warning of an unknown property being used
+     */
+    protected void validatePropertyName(String name) {
+    }
+
+    /**
+     * Allow implementations to validate whether a property name is valid
+     * and either throw an exception or log a warning of an unknown property being used
+     * and to convert the given value to the correct type before updating the value.
+     */
+    protected Object validatePropertyValue(String name, Object value) {
+        validatePropertyName(name);
+        return value;
+    }
+
+
+}

Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ComponentConfigurationSupport.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultComponent.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultComponent.java?rev=1470840&r1=1470839&r2=1470840&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultComponent.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultComponent.java Tue Apr 23 08:00:07 2013
@@ -23,6 +23,7 @@ import java.util.Map;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Component;
+import org.apache.camel.ComponentConfiguration;
 import org.apache.camel.Endpoint;
 import org.apache.camel.EndpointConfiguration;
 import org.apache.camel.ResolveEndpointFailedException;
@@ -138,6 +139,11 @@ public abstract class DefaultComponent e
         return endpoint;
     }
 
+    @Override
+    public ComponentConfiguration createComponentConfiguration() {
+        return new DefaultComponentConfiguration(this);
+    }
+
     public EndpointConfiguration createConfiguration(String uri) throws Exception {
         MappedEndpointConfiguration config = new MappedEndpointConfiguration(getCamelContext());
         config.setURI(new URI(uri));

Added: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultComponentConfiguration.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultComponentConfiguration.java?rev=1470840&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultComponentConfiguration.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultComponentConfiguration.java Tue Apr 23 08:00:07 2013
@@ -0,0 +1,84 @@
+/**
+ *
+ * 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.impl;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.camel.Component;
+import org.apache.camel.Endpoint;
+import org.apache.camel.InvalidPropertyException;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.util.IntrospectionSupport;
+
+/**
+ * Default implementation for components which do not inherit from {@link UriEndpointComponent} and
+ * do not have Endpoint classes annotated with {@link org.apache.camel.spi.UriEndpoint}
+ */
+public class DefaultComponentConfiguration extends ComponentConfigurationSupport {
+    public DefaultComponentConfiguration(Component component) {
+        super(component);
+    }
+
+    @Override
+    public Object getEndpointParameter(Endpoint endpoint, String name) throws RuntimeCamelException {
+        try {
+            return IntrospectionSupport.getProperty(endpoint, name);
+        } catch (Exception e) {
+            throw new RuntimeCamelException(
+                    "Failed to get property " + name + " on endpoint " + endpoint + " due to " + e, e);
+        }
+    }
+
+    @Override
+    public void setEndpointParameter(Endpoint endpoint, String name, Object value)
+            throws RuntimeCamelException {
+        boolean answer = false;
+        try {
+            answer = IntrospectionSupport.setProperty(endpoint, name, value);
+        } catch (Exception e) {
+            throw new RuntimeCamelException(
+                    "Failed to set property " + name + " with value " + value + " on endpoint " + endpoint
+                            + " due to " + e, e);
+        }
+        if (!answer) {
+            throw new InvalidPropertyException(endpoint, name);
+        }
+    }
+
+    /**
+     * Since we have no parameter metadata lets just return parameter configurations for each parameter we
+     * have right now.
+     *
+     * @return configurations for each current property value
+     */
+    @Override
+    public SortedMap<String, ParameterConfiguration> getParameterConfigurationMap() {
+        SortedMap<String, ParameterConfiguration> answer = new TreeMap<String, ParameterConfiguration>();
+        Set<Map.Entry<String, Object>> entries = getParameters().entrySet();
+        for (Map.Entry<String, Object> entry : entries) {
+            String name = entry.getKey();
+            Object value = entry.getValue();
+            Class<?> type = (value != null) ? value.getClass() : String.class;
+            answer.put(name, new ParameterConfiguration(name, type));
+        }
+        return answer;
+    }
+}

Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultComponentConfiguration.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ParameterConfiguration.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ParameterConfiguration.java?rev=1470840&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ParameterConfiguration.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ParameterConfiguration.java Tue Apr 23 08:00:07 2013
@@ -0,0 +1,64 @@
+/**
+ *
+ * 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.impl;
+
+import java.lang.reflect.Field;
+
+import org.apache.camel.spi.UriParam;
+
+/**
+ * Represents the configuration of a URI query parameter value to allow type conversion
+ * and better validation of the configuration of URIs and Endpoints
+ */
+public class ParameterConfiguration {
+    private final String name;
+    private final Class<?> parameterType;
+
+    public ParameterConfiguration(String name, Class<?> parameterType) {
+        this.name = name;
+        this.parameterType = parameterType;
+    }
+
+    @Override
+    public String toString() {
+        return "ParameterConfiguration[" + name + " on " + parameterType + "]";
+    }
+
+    /**
+     * Returns the name of the parameter value
+     *
+     * @return
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the type of the parameter value
+     */
+    public Class<?> getParameterType() {
+        return parameterType;
+    }
+
+    /**
+     * Factory method to create a new ParameterConfiguration from a field
+     */
+    public static ParameterConfiguration newInstance(String name, Field field, UriParam uriParam) {
+        return new AnnotatedParameterConfiguration(name, field.getType(), field);
+    }
+}

Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ParameterConfiguration.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriComponentConfiguration.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriComponentConfiguration.java?rev=1470840&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriComponentConfiguration.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriComponentConfiguration.java Tue Apr 23 08:00:07 2013
@@ -0,0 +1,158 @@
+/**
+ *
+ * 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.impl;
+
+import java.util.Collections;
+import java.util.SortedMap;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.Endpoint;
+import org.apache.camel.InvalidPropertyException;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.util.IntrospectionSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implements {@link org.apache.camel.EndpointConfiguration} for Endpoint implementations
+ * which are annotated with {@link UriEndpoint}
+ * to use the {@link org.apache.camel.spi.UriParam} and {@link org.apache.camel.spi.UriParams} annotations
+ * to denote its parameters which can be specified via URI query parameters.
+ */
+public class UriComponentConfiguration extends ComponentConfigurationSupport {
+    private static final transient Logger LOG = LoggerFactory.getLogger(UriComponentConfiguration.class);
+
+    private final Class<? extends Endpoint> endpointClass;
+    private final SortedMap<String, ParameterConfiguration> parameterConfigurationMap;
+    private boolean strictOnParameterNames = true;
+
+    public UriComponentConfiguration(Component component, Class<? extends Endpoint> endpointClass,
+                                     SortedMap<String, ParameterConfiguration> parameterConfigurationMap) {
+        super(component);
+        this.endpointClass = endpointClass;
+        this.parameterConfigurationMap = Collections.unmodifiableSortedMap(parameterConfigurationMap);
+    }
+
+    public UriComponentConfiguration(Component component, Class<? extends Endpoint> endpointClass) {
+        this(component, endpointClass, UriEndpointComponent.createParameterConfigurationMap(endpointClass));
+    }
+
+    public UriComponentConfiguration(UriEndpointComponent component) {
+        this(component, component.getEndpointClass(), component.getParameterConfigurationMap());
+    }
+
+    @Override
+    public Object getEndpointParameter(Endpoint endpoint, String name) throws RuntimeCamelException {
+        ParameterConfiguration config = getParameterConfiguration(name);
+
+        // lets try get the property regardless of if this maps to a valid property name
+        // then if the introspection fails we will get a valid error otherwise
+        // lets raise a warning afterwards that we should update the metadata on the endpoint class
+        Object answer = null;
+        try {
+            answer = IntrospectionSupport.getProperty(endpoint, name);
+        } catch (Exception e) {
+            throw new RuntimeCamelException(
+                    "Failed to get property '" + name + "' on " + endpoint + " due " + e.getMessage(), e);
+        }
+        if (config == null) {
+            unknownPropertyName(name);
+        }
+        return answer;
+    }
+
+    @Override
+    public void setEndpointParameter(Endpoint endpoint, String name, Object value)
+            throws RuntimeCamelException {
+        ParameterConfiguration config = getParameterConfiguration(name);
+
+        // lets try set the property regardless of if this maps to a valid property name
+        // then if the injection fails we will get a valid error otherwise
+        // lets raise a warning afterwards that we should update the metadata on the endpoint class
+        try {
+            IntrospectionSupport.setProperty(endpoint, name, value);
+        } catch (Exception e) {
+            throw new RuntimeCamelException(
+                    "Failed to set property '" + name + "' on " + endpoint + " to value " + value + " due "
+                            + e.getMessage(), e);
+        }
+        if (config == null) {
+            unknownPropertyName(name);
+        }
+    }
+
+    public CamelContext getCamelContext() {
+        return component.getCamelContext();
+    }
+
+    public Class<? extends Endpoint> getEndpointClass() {
+        return endpointClass;
+    }
+
+    public boolean isStrictOnParameterNames() {
+        return strictOnParameterNames;
+    }
+
+    /**
+     * Strict mode is enabled by default but if disabled then invalid parameter names
+     * will not result in exceptions but we will just log warnings about their use
+     *
+     * @param strictOnParameterNames whether to throw exceptions if invalid
+     *                               parameter names are used or not
+     */
+    public void setStrictOnParameterNames(boolean strictOnParameterNames) {
+        this.strictOnParameterNames = strictOnParameterNames;
+    }
+
+    @Override
+    public SortedMap<String, ParameterConfiguration> getParameterConfigurationMap() {
+        return parameterConfigurationMap;
+    }
+
+    @Override
+    protected void validatePropertyName(String name) {
+        ParameterConfiguration parameterConfiguration = getParameterConfiguration(name);
+        if (parameterConfiguration == null) {
+            unknownPropertyName(name);
+        }
+    }
+
+    @Override
+    protected Object validatePropertyValue(String name, Object value) {
+        ParameterConfiguration parameterConfiguration = getParameterConfiguration(name);
+        if (parameterConfiguration == null) {
+            unknownPropertyName(name);
+            return value;
+        } else {
+            Class<?> parameterType = parameterConfiguration.getParameterType();
+            return getCamelContext().getTypeConverter().convertTo(parameterType, value);
+        }
+    }
+
+    protected void unknownPropertyName(String name) {
+        if (isStrictOnParameterNames()) {
+            throw new InvalidPropertyException(this, name, endpointClass);
+        } else {
+            LOG.warn("Using parameter " + name + " on endpoint " + getEndpointClass().getName()
+                    + " which does not have a @UriParam annotation! " +
+                    "Please add the @UriParam annotation to the " + name + "field");
+        }
+    }
+
+}

Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriComponentConfiguration.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriEndpointComponent.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriEndpointComponent.java?rev=1470840&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriEndpointComponent.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriEndpointComponent.java Tue Apr 23 08:00:07 2013
@@ -0,0 +1,122 @@
+/**
+ *
+ * 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.impl;
+
+import java.lang.reflect.Field;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ComponentConfiguration;
+import org.apache.camel.Endpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.ReflectionHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A component implementation for endpoints which are annotated with UriEndpoint to describe
+ * their configurable parameters via annotations
+ */
+public abstract class UriEndpointComponent extends DefaultComponent {
+    private static final transient Logger LOG = LoggerFactory.getLogger(UriEndpointComponent.class);
+
+    private final Class<? extends Endpoint> endpointClass;
+    private SortedMap<String, ParameterConfiguration> parameterConfigurationMap;
+
+    public UriEndpointComponent(Class<? extends Endpoint> endpointClass) {
+        this.endpointClass = endpointClass;
+    }
+
+    public UriEndpointComponent(CamelContext context, Class<? extends Endpoint> endpointClass) {
+        super(context);
+        this.endpointClass = endpointClass;
+    }
+
+    @Override
+    public ComponentConfiguration createComponentConfiguration() {
+        return new UriComponentConfiguration(this);
+    }
+
+    /**
+     * Returns a newly created sorted map, indexed by name of all the parameter configurations
+     * of the given endpoint class using introspection for the various annotations like
+     * {@link org.apache.camel.spi.UriEndpoint}, {@link org.apache.camel.spi.UriParam}, {@link org.apache.camel.spi.UriParams}
+     */
+    public static SortedMap<String, ParameterConfiguration> createParameterConfigurationMap(
+            Class<? extends Endpoint> endpointClass) {
+        SortedMap<String, ParameterConfiguration> answer = new TreeMap<String, ParameterConfiguration>();
+        populateParameterConfigurationMap(answer, endpointClass, "");
+        return answer;
+    }
+
+    protected static void populateParameterConfigurationMap(
+            final SortedMap<String, ParameterConfiguration> parameterMap, Class<?> aClass,
+            final String prefix) {
+        ReflectionHelper.doWithFields(aClass, new ReflectionHelper.FieldCallback() {
+            @Override
+            public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
+                UriParam uriParam = field.getAnnotation(UriParam.class);
+                if (uriParam != null) {
+                    String name = uriParam.name();
+                    if (ObjectHelper.isEmpty(name)) {
+                        name = field.getName();
+                    }
+                    String propertyName = prefix + name;
+
+                    // is the parameter a nested configuration object
+                    Class<?> fieldType = field.getType();
+                    UriParams uriParams = fieldType.getAnnotation(UriParams.class);
+                    if (uriParams != null) {
+                        String nestedPrefix = uriParams.prefix();
+                        if (nestedPrefix == null) {
+                            nestedPrefix = "";
+                        }
+                        nestedPrefix = (prefix + nestedPrefix).trim();
+                        populateParameterConfigurationMap(parameterMap, fieldType, nestedPrefix);
+                    } else {
+                        if (parameterMap.containsKey(propertyName)) {
+                            LOG.warn(
+                                    "Duplicate property name " + propertyName + " defined on field " + field);
+                        } else {
+                            parameterMap.put(propertyName,
+                                    ParameterConfiguration.newInstance(propertyName, field, uriParam));
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    public Class<? extends Endpoint> getEndpointClass() {
+        return endpointClass;
+    }
+
+    /**
+     * Returns the sorted map of all the URI query parameter names to their {@link ParameterConfiguration} objects
+     */
+    public SortedMap<String, ParameterConfiguration> getParameterConfigurationMap() {
+        if (parameterConfigurationMap == null) {
+            parameterConfigurationMap = createParameterConfigurationMap(getEndpointClass());
+        }
+        return new TreeMap<String, ParameterConfiguration>(parameterConfigurationMap);
+    }
+
+}

Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriEndpointComponent.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriEndpointConfiguration.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriEndpointConfiguration.java?rev=1470840&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriEndpointConfiguration.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriEndpointConfiguration.java Tue Apr 23 08:00:07 2013
@@ -0,0 +1,149 @@
+/**
+ *
+ * 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.impl;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.EndpointConfiguration;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.apache.camel.util.IntrospectionSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implements {@link EndpointConfiguration} for Endpoint implementations
+ * which are annotated with {@link UriEndpoint} to use the {@link UriParam} and {@link UriParams} annotations
+ * to denote its parameters which can be specified via URI query parameters.
+ */
+public class UriEndpointConfiguration implements EndpointConfiguration {
+    private static final transient Logger LOG = LoggerFactory.getLogger(UriEndpointConfiguration.class);
+
+    private final CamelContext camelContext;
+    private final Endpoint endpoint;
+    private String uriText;
+    private URI uri;
+    private SortedMap<String, ParameterConfiguration> propertyMap;
+
+    public UriEndpointConfiguration(CamelContext camelContext, Endpoint endpoint, String uriText) {
+        this.camelContext = camelContext;
+        this.endpoint = endpoint;
+        this.uriText = uriText;
+    }
+
+    @Override
+    public URI getURI() {
+        if (uri == null) {
+            // lazily create the URI which may fail as not all camel uriText are valid URI text
+            try {
+                uri = new URI(uriText);
+            } catch (URISyntaxException e) {
+                throw new RuntimeCamelException(e);
+            }
+        }
+        return uri;
+    }
+
+    public void setURI(URI uri) {
+        this.uriText = null;
+        this.uri = uri;
+    }
+
+    @Override
+    public <T> T getParameter(String name) throws RuntimeCamelException {
+        ParameterConfiguration config = getPropertyConfiguration(name);
+
+        // lets try get the property regardless of if this maps to a valid property name
+        // then if the introspection fails we will get a valid error otherwise
+        // lets raise a warning afterwards that we should update the metadata on the endpoint class
+        T answer;
+        try {
+            answer = (T)IntrospectionSupport.getProperty(endpoint, name);
+        } catch (Exception e) {
+            throw new RuntimeCamelException(
+                    "Failed to get property '" + name + "' on " + endpoint + " due " + e.getMessage(), e);
+        }
+        if (config == null) {
+            warnMissingUriParamOnProperty(name);
+        }
+        return answer;
+    }
+
+    protected void warnMissingUriParamOnProperty(String name) {
+        LOG.warn("Using property " + name + " on endpoint " + getEndpointClass().getName()
+                + " which does not have a @UriParam annotation! " +
+                "Please add the @UriParam annotation to the " + name + "field");
+    }
+
+    @Override
+    public <T> void setParameter(String name, T value) throws RuntimeCamelException {
+        ParameterConfiguration config = getPropertyConfiguration(name);
+
+        // lets try set the property regardless of if this maps to a valid property name
+        // then if the injection fails we will get a valid error otherwise
+        // lets raise a warning afterwards that we should update the metadata on the endpoint class
+        try {
+            IntrospectionSupport.setProperty(endpoint, name, value);
+        } catch (Exception e) {
+            throw new RuntimeCamelException(
+                    "Failed to set property '" + name + "' on " + endpoint + " to value " + value + " due "
+                            + e.getMessage(), e);
+        }
+        if (config == null) {
+            warnMissingUriParamOnProperty(name);
+        }
+    }
+
+    @Override
+    public String toUriString(UriFormat format) {
+        // TODO
+        return null;
+    }
+
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    public Class<? extends Endpoint> getEndpointClass() {
+        return endpoint.getClass();
+    }
+
+    /**
+     * Returns the property configuration for the given property name or null if it does not exist
+     */
+    public ParameterConfiguration getPropertyConfiguration(String name) {
+        return getPropertyConfigurationMap().get(name);
+    }
+
+    /**
+     * Returns the sorted map of all the property names to their {@link ParameterConfiguration} objects
+     */
+    public SortedMap<String, ParameterConfiguration> getPropertyConfigurationMap() {
+        if (propertyMap == null) {
+            propertyMap = UriEndpointComponent.createParameterConfigurationMap(getEndpointClass());
+        }
+        return new TreeMap<String, ParameterConfiguration>(propertyMap);
+    }
+
+}

Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/UriEndpointConfiguration.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/camel-core/src/test/java/org/apache/camel/impl/ComponentConfigurationTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/impl/ComponentConfigurationTest.java?rev=1470840&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/impl/ComponentConfigurationTest.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/impl/ComponentConfigurationTest.java Tue Apr 23 08:00:07 2013
@@ -0,0 +1,421 @@
+/**
+ *
+ * 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.impl;
+
+import java.util.Map;
+import java.util.SortedMap;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.ComponentConfiguration;
+import org.apache.camel.Consumer;
+import org.apache.camel.Endpoint;
+import org.apache.camel.InvalidPropertyException;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.ResolveEndpointFailedException;
+import org.apache.camel.TestSupport;
+import org.apache.camel.component.seda.SedaComponent;
+import org.apache.camel.component.seda.SedaEndpoint;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests the use of {@link ComponentConfiguration} both from the URI string approach or for creating and mutating Endpoint instances
+ * with both regular Components/Endpoints and {@link UriEndpointComponent} instances which have Endpoints annotated
+ * with {@link org.apache.camel.spi.UriEndpoint}, {@link org.apache.camel.spi.UriParam} and {@link org.apache.camel.spi.UriParams}
+ */
+public class ComponentConfigurationTest {
+    private static final transient Logger LOG = LoggerFactory.getLogger(ComponentConfigurationTest.class);
+
+    private CamelContext context;
+
+    @Before
+    public void createContext() throws Exception {
+        context = new DefaultCamelContext();
+        context.addComponent("cheese", new NonUriComponent());
+        context.start(); // so that TypeConverters are available
+    }
+
+    @After
+    public void destroyContext() throws Exception {
+        context.stop();
+        context = null;
+    }
+
+    /**
+     * Show we can create a URI from the base URI and the underlying query parameter values
+     */
+    @Test
+    public void testCreateUriStringFromParameters() throws Exception {
+        Component component = context.getComponent("seda");
+        ComponentConfiguration configuration = component.createComponentConfiguration();
+        assertNotNull("Should have created a ComponentConfiguration for component " + component,
+                configuration);
+
+        // configure the base URI properties
+        configuration.setBaseUri("foo");
+
+        // lets try set and get a valid parameter
+        configuration.setParameter("concurrentConsumers", 5);
+        configuration.setParameter("size", 1000);
+
+        String uriString = configuration.getUriString();
+        assertEquals("uriString", "foo?concurrentConsumers=5&size=1000", uriString);
+    }
+
+    /**
+     * Show we can create a URI from the base URI and the underlying query parameter values
+     * on any endpoint (even if its not a {@link UriEndpointComponent})
+     */
+    @Test
+    public void testCreateUriStringFromParametersOnDefaultComponent() throws Exception {
+        Component component = context.getComponent("cheese");
+        ComponentConfiguration configuration = component.createComponentConfiguration();
+        assertNotNull("Should have created a ComponentConfiguration for component " + component,
+                configuration);
+
+        // configure the base URI properties
+        configuration.setBaseUri("somePath");
+
+        // lets try set and get a valid parameter
+        configuration.setParameter("foo", "something");
+        configuration.setParameter("bar", 123);
+
+        String uriString = configuration.getUriString();
+        assertEquals("uriString", "somePath?bar=123&foo=something", uriString);
+    }
+
+    /**
+     * Test that parameters are strictly typed on {@link UriEndpointComponent}s
+     */
+    @Test
+    public void testSetParametersFromUriString() throws Exception {
+        Component component = context.getComponent("seda");
+        ComponentConfiguration configuration = component.createComponentConfiguration();
+        assertNotNull("Should have created a ComponentConfiguration for component " + component,
+                configuration);
+
+        // configure the uri and query parameters
+        configuration.setUriString("foo?concurrentConsumers=5&size=1000");
+
+        // notice the parameters are all correctly typed due to the use of a UriEndpointComponent
+        // and the associated @UriEndpoint / @UriParam annotations
+        assertEquals("concurrentConsumers", 5, configuration.getParameter("concurrentConsumers"));
+        assertEquals("size", 1000, configuration.getParameter("size"));
+
+        configuration.setUriString("foo?concurrentConsumers=9&size=2000");
+
+        assertEquals("concurrentConsumers", 9, configuration.getParameter("concurrentConsumers"));
+        assertEquals("size", 2000, configuration.getParameter("size"));
+    }
+
+    /**
+     * Tests that parameters can be used on non-{@link UriEndpointComponent} implementations
+     * but that their types tend to be String until we try to create an Endpoint
+     */
+    @Test
+    public void testSetParametersFromUriStringOnDefaultComponent() throws Exception {
+        Component component = context.getComponent("cheese");
+        ComponentConfiguration configuration = component.createComponentConfiguration();
+        assertNotNull("Should have created a ComponentConfiguration for component " + component,
+                configuration);
+
+        // configure the uri and query parameters
+        configuration.setUriString("somePath?foo=something&bar=123");
+
+        // notice the parameters are all Strings since we don't use UriEndpointComponent
+        assertEquals("foo", "something", configuration.getParameter("foo"));
+        assertEquals("bar", "123", configuration.getParameter("bar"));
+
+        configuration.setUriString("somePath?foo=another&bar=456");
+
+        assertEquals("foo", "another", configuration.getParameter("foo"));
+        assertEquals("bar", "456", configuration.getParameter("bar"));
+    }
+
+    /**
+     * Use the {@link ComponentConfiguration}, set some parameters then lets turn it into an endpoint
+     */
+    @Test
+    public void testCreateNewSedaUriEndpoint() throws Exception {
+        Component component = context.getComponent("seda");
+        ComponentConfiguration configuration = component.createComponentConfiguration();
+        assertNotNull("Should have created a ComponentConfiguration for component " + component,
+                configuration);
+
+        // configure the base URI properties
+        configuration.setBaseUri("foo");
+
+        // lets try set and get a valid parameter
+        configuration.setParameter("concurrentConsumers", 5);
+        configuration.setParameter("size", 1000);
+
+        // lets try set an invalid parameter
+        try {
+            configuration.setParameter("doesNotExist", 1000);
+            fail("Should have got InvalidPropertyException thrown!");
+        } catch (InvalidPropertyException e) {
+            System.out.println("Got expected exception: " + e);
+        }
+
+        SedaEndpoint endpoint = TestSupport
+                .assertIsInstanceOf(SedaEndpoint.class, configuration.createEndpoint());
+        assertEquals("concurrentConsumers", 5, endpoint.getConcurrentConsumers());
+        assertEquals("size", 1000, endpoint.getSize());
+
+        assertEquals("endpoint uri", "foo?concurrentConsumers=5&size=1000", endpoint.getEndpointUri());
+
+        // lets try configure a parameter
+        configuration.setEndpointParameter(endpoint, "concurrentConsumers", 6);
+        assertEquals("concurrentConsumers", 6, endpoint.getConcurrentConsumers());
+
+        // lets try set an invalid parameter
+        try {
+            configuration.setEndpointParameter(endpoint, "doesNotExist", 1000);
+            fail("Should have got InvalidPropertyException thrown!");
+        } catch (InvalidPropertyException e) {
+            System.out.println("Got expected exception: " + e);
+        }
+    }
+
+    @Test
+    public void testCreateNewDefaultComponentEndpoint() throws Exception {
+        Component component = context.getComponent("cheese");
+        ComponentConfiguration configuration = component.createComponentConfiguration();
+        assertNotNull("Should have created a ComponentConfiguration for component " + component,
+                configuration);
+
+        // configure the base URI properties
+        configuration.setBaseUri("something");
+
+        // lets try set and get a valid parameter
+        configuration.setParameter("foo", "xyz");
+        configuration.setParameter("bar", 5);
+
+        NonUriEndpoint endpoint = TestSupport
+                .assertIsInstanceOf(NonUriEndpoint.class, configuration.createEndpoint());
+        assertEquals("foo", "xyz", endpoint.getFoo());
+        assertEquals("bar", 5, endpoint.getBar());
+
+        System.out.println("Created endpoint " + endpoint + " on URI " + endpoint.getEndpointUri());
+
+        // lets try configure a parameter
+        configuration.setEndpointParameter(endpoint, "bar", 6);
+        assertEquals("bar", 6, endpoint.getBar());
+
+        // lets try configure an invalid parameter
+        try {
+            configuration.setEndpointParameter(endpoint, "doesNotExist", 1000);
+            fail("Should have got InvalidPropertyException thrown!");
+        } catch (InvalidPropertyException e) {
+            System.out.println("Got expected exception: " + e);
+        }
+
+        ComponentConfiguration badConfiguration = component.createComponentConfiguration();
+        badConfiguration.setBaseUri(configuration.getBaseUri());
+        badConfiguration.setParameters(configuration.getParameters());
+
+        // lets try set an invalid parameter on a configuration
+        // there is no way to validate on non UriEndpoint unless the endpoint
+        // creates its own configuration object so this always works...
+        badConfiguration.setParameter("doesNotExist", 1000);
+
+        // however it fails if we now try create an
+        try {
+            badConfiguration.createEndpoint();
+            fail("Should have got ResolveEndpointFailedException thrown!");
+        } catch (ResolveEndpointFailedException e) {
+            System.out.println("Got expected exception: " + e);
+        }
+
+    }
+
+    /**
+     * Shows we can introspect a {@link UriEndpointComponent} and find all the available parameters
+     * along with their types and {@link ParameterConfiguration}
+     */
+    @Test
+    public void testIntrospectSedaEndpointParameters() throws Exception {
+        Component component = context.getComponent("seda");
+        ComponentConfiguration configuration = component.createComponentConfiguration();
+        assertNotNull("Should have created a ComponentConfiguration for component " + component,
+                configuration);
+
+        SortedMap<String, ParameterConfiguration> parameterMap = configuration.getParameterConfigurationMap();
+        assertTrue("getParameterConfigurationMap() should not be empty!", !parameterMap.isEmpty());
+
+        ParameterConfiguration concurrentConsumersConfig = parameterMap.get("concurrentConsumers");
+        assertNotNull("parameterMap[concurrentConsumers] should not be null!", concurrentConsumersConfig);
+        assertEquals("concurrentConsumersConfig.getName()", "concurrentConsumers",
+                concurrentConsumersConfig.getName());
+        assertEquals("concurrentConsumersConfig.getParameterType()", int.class,
+                concurrentConsumersConfig.getParameterType());
+
+        System.out.println(component + " has has configuration properties " + parameterMap.keySet());
+    }
+
+    /**
+     * Shows we can introspect the parameters of a DefaultComponent (i.e. a non {@link UriEndpointComponent})
+     * though we only get to introspect the parameter values from teh current configuration
+     */
+    @Test
+    public void testIntrospectDefaultComponentParameters() throws Exception {
+        Component component = context.getComponent("cheese");
+        ComponentConfiguration configuration = component.createComponentConfiguration();
+        assertNotNull("Should have created a ComponentConfiguration for component " + component,
+                configuration);
+
+        SortedMap<String, ParameterConfiguration> parameterMap = configuration.getParameterConfigurationMap();
+        assertTrue("getParameterConfigurationMap() should be empty as we have no parameters yet",
+                parameterMap.isEmpty());
+
+        // configure the uri and query parameters
+        configuration.setUriString("somePath?foo=something&bar=123");
+
+        parameterMap = configuration.getParameterConfigurationMap();
+        assertEquals("getParameterConfigurationMap() size", 2, parameterMap.size());
+        ParameterConfiguration barConfiguration = configuration.getParameterConfiguration("bar");
+        assertNotNull("should hav a configuration for 'bar'", barConfiguration);
+        assertEquals("barConfiguration.getName()", "bar", barConfiguration.getName());
+        assertEquals("barConfiguration.getParameterType()", String.class,
+                barConfiguration.getParameterType());
+    }
+
+    /**
+     * Shows how we can use the configuration to get and set parameters directly on the endpoint
+     * for a {@link UriEndpointComponent}
+     */
+    @Test
+    public void testConfigureAnExistingSedaEndpoint() throws Exception {
+        SedaEndpoint endpoint = context.getEndpoint("seda:cheese?concurrentConsumers=5", SedaEndpoint.class);
+        SedaComponent component = endpoint.getComponent();
+        ComponentConfiguration configuration = component.createComponentConfiguration();
+
+        assertEquals("concurrentConsumers", 5, endpoint.getConcurrentConsumers());
+        assertEquals("concurrentConsumers", 5,
+                configuration.getEndpointParameter(endpoint, "concurrentConsumers"));
+
+        // lets try set and get some valid parameters
+        configuration.setEndpointParameter(endpoint, "concurrentConsumers", 10);
+        Object concurrentConsumers = configuration.getEndpointParameter(endpoint, "concurrentConsumers");
+        assertEquals("endpoint.concurrentConsumers", 10, concurrentConsumers);
+
+        configuration.setEndpointParameter(endpoint, "size", 1000);
+        Object size = configuration.getEndpointParameter(endpoint, "size");
+        assertEquals("endpoint.size", 1000, size);
+
+        // lets try set an invalid parameter
+        try {
+            configuration.setEndpointParameter(endpoint, "doesNotExist", 1000);
+            fail("Should have got InvalidPropertyException thrown!");
+        } catch (InvalidPropertyException e) {
+            System.out.println("Got expected exception: " + e);
+        }
+    }
+
+
+    /**
+     * Shows how we can use the configuration to get and set parameters directly on the endpoint
+     * which is typesafe and performs validation even if the component is not a {@link UriEndpointComponent}
+     */
+    @Test
+    public void testConfigureAnExistingDefaultEndpoint() throws Exception {
+        NonUriEndpoint endpoint = context
+                .getEndpoint("cheese:somePath?bar=123&foo=something", NonUriEndpoint.class);
+        Component component = endpoint.getComponent();
+        ComponentConfiguration configuration = component.createComponentConfiguration();
+
+        assertEquals("bar", 123, endpoint.getBar());
+        assertEquals("bar", 123, configuration.getEndpointParameter(endpoint, "bar"));
+
+        // lets try set and get some valid parameters
+        configuration.setEndpointParameter(endpoint, "bar", 10);
+        Object bar = configuration.getEndpointParameter(endpoint, "bar");
+        assertEquals("endpoint.bar", 10, bar);
+
+        configuration.setEndpointParameter(endpoint, "foo", "anotherThing");
+        Object foo = configuration.getEndpointParameter(endpoint, "foo");
+        assertEquals("endpoint.foo", "anotherThing", foo);
+
+        // lets try set an invalid parameter
+        try {
+            configuration.setEndpointParameter(endpoint, "doesNotExist", 1000);
+            fail("Should have got InvalidPropertyException thrown!");
+        } catch (InvalidPropertyException e) {
+            System.out.println("Got expected exception: " + e);
+        }
+    }
+
+    public static class NonUriComponent extends DefaultComponent {
+        @Override
+        protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters)
+                throws Exception {
+            return new NonUriEndpoint(uri, this);
+        }
+
+    }
+
+    public static class NonUriEndpoint extends DefaultEndpoint {
+        private String foo;
+        private int bar;
+
+        public NonUriEndpoint(String uri, NonUriComponent component) {
+            super(uri, component);
+        }
+
+        public int getBar() {
+            return bar;
+        }
+
+        public void setBar(int bar) {
+            this.bar = bar;
+        }
+
+        public String getFoo() {
+            return foo;
+        }
+
+        public void setFoo(String foo) {
+            this.foo = foo;
+        }
+
+        @Override
+        public Producer createProducer() throws Exception {
+            return null;
+        }
+
+        @Override
+        public Consumer createConsumer(Processor processor) throws Exception {
+            return null;
+        }
+
+        @Override
+        public boolean isSingleton() {
+            return false;
+        }
+    }
+}

Propchange: camel/trunk/camel-core/src/test/java/org/apache/camel/impl/ComponentConfigurationTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/impl/ConfigurationHelperTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/impl/ConfigurationHelperTest.java?rev=1470840&r1=1470839&r2=1470840&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/impl/ConfigurationHelperTest.java (original)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/impl/ConfigurationHelperTest.java Tue Apr 23 08:00:07 2013
@@ -22,6 +22,7 @@ import java.util.Map;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Component;
+import org.apache.camel.ComponentConfiguration;
 import org.apache.camel.Endpoint;
 import org.apache.camel.EndpointConfiguration;
 import org.apache.camel.URIField;
@@ -35,6 +36,9 @@ import static org.junit.Assert.assertEqu
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+/**
+ * @see ComponentConfigurationTest for tests using the {@link ComponentConfiguration} mechanism
+ */
 public class ConfigurationHelperTest {
 
     private static final transient Logger LOG = LoggerFactory.getLogger(ConfigurationHelperTest.class);
@@ -231,6 +235,11 @@ public class ConfigurationHelperTest {
         }
 
         @Override
+        public ComponentConfiguration createComponentConfiguration() {
+            return null;
+        }
+
+        @Override
         public EndpointConfiguration createConfiguration(String uri) throws Exception {
             if (uri.equals(URIDUMP_SCHEME)) {
                 return new UriDumpConfiguration(getCamelContext());

Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/impl/EndpointConfigurationTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/impl/EndpointConfigurationTest.java?rev=1470840&r1=1470839&r2=1470840&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/impl/EndpointConfigurationTest.java (original)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/impl/EndpointConfigurationTest.java Tue Apr 23 08:00:07 2013
@@ -18,6 +18,7 @@ package org.apache.camel.impl;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Component;
+import org.apache.camel.ComponentConfiguration;
 import org.apache.camel.Endpoint;
 import org.apache.camel.EndpointConfiguration;
 import org.junit.AfterClass;
@@ -88,6 +89,11 @@ public class EndpointConfigurationTest {
         }
 
         @Override
+        public ComponentConfiguration createComponentConfiguration() {
+            return null;
+        }
+
+        @Override
         public EndpointConfiguration createConfiguration(String uri) throws Exception {
             return new MappedEndpointConfiguration(getCamelContext());
         }