You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by dh...@apache.org on 2014/06/10 21:51:50 UTC

[22/35] git commit: Updated archetype files to first real implementation

Updated archetype files to first real implementation


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/911e5413
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/911e5413
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/911e5413

Branch: refs/heads/master
Commit: 911e541323c16386371faedeb0a55f35b7ed3e9b
Parents: 96c8ec0
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Wed Jun 4 13:55:36 2014 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Tue Jun 10 12:48:33 2014 -0700

----------------------------------------------------------------------
 .../META-INF/maven/archetype-metadata.xml       |   3 +
 .../__artifactId__-api/pom.xml                  |   8 +
 .../__artifactId__-component/pom.xml            |  12 ++
 .../src/main/java/__name__Component.java        |  76 ++++++++-
 .../src/main/java/__name__Configuration.java    |  28 ++++
 .../src/main/java/__name__Consumer.java         | 119 +++++++++++++-
 .../src/main/java/__name__Endpoint.java         | 160 ++++++++++++++++++-
 .../src/main/java/__name__Producer.java         | 155 +++++++++++++++++-
 .../main/java/internal/__name__Constants.java   |  29 ++++
 .../java/internal/__name__PropertiesHelper.java |  40 +++++
 10 files changed, 609 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/911e5413/tooling/archetypes/camel-archetype-api-component/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml b/tooling/archetypes/camel-archetype-api-component/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
index 96b096c..f597ef5 100644
--- a/tooling/archetypes/camel-archetype-api-component/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
@@ -37,6 +37,9 @@
     <requiredProperty key="maven-bundle-plugin-version">
       <defaultValue>${maven-bundle-plugin-version}</defaultValue>
     </requiredProperty>
+    <requiredProperty key="maven-javadoc-plugin-version">
+      <defaultValue>${maven-javadoc-plugin-version}</defaultValue>
+    </requiredProperty>
     <requiredProperty key="build-helper-maven-plugin-version">
       <defaultValue>${build-helper-maven-plugin-version}</defaultValue>
     </requiredProperty>

http://git-wip-us.apache.org/repos/asf/camel/blob/911e5413/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/pom.xml b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/pom.xml
index 632a897..c4af2c8 100644
--- a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/pom.xml
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/pom.xml
@@ -50,6 +50,14 @@
             <goals>
               <goal>jar</goal>
             </goals>
+            <configuration>
+              <attach>true</attach>
+              <source>1.6</source>
+              <quiet>true</quiet>
+              <detectOfflineLinks>false</detectOfflineLinks>
+              <javadocVersion>1.6</javadocVersion>
+              <encoding>UTF-8</encoding>
+            </configuration>
           </execution>
         </executions>
       </plugin>

http://git-wip-us.apache.org/repos/asf/camel/blob/911e5413/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/pom.xml b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/pom.xml
index f724e37..af32397 100644
--- a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/pom.xml
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/pom.xml
@@ -197,6 +197,18 @@
                 <api>
                   <apiName>hello1</apiName>
                   <proxyClass>${package}.${name}FileSigApi</proxyClass>
+                  <!-- Use method aliases in endpoint URIs, e.g. support 'widget' as alias for getWidget or setWidget
+                  <aliases>
+                    <alias>
+                      <methodPattern>get(.+)</methodPattern>
+                      <methodAlias>$1</methodAlias>
+                    </alias>
+                    <alias>
+                      <methodPattern>set(.+)</methodPattern>
+                      <methodAlias>$1</methodAlias>
+                    </alias>
+                  </aliases>
+                  -->
                 </api>
                 <api>
                   <apiName>hello2</apiName>

http://git-wip-us.apache.org/repos/asf/camel/blob/911e5413/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Component.java
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Component.java b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Component.java
index a87f1f4..7226fef 100644
--- a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Component.java
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Component.java
@@ -16,19 +16,89 @@
 ## ------------------------------------------------------------------------
 package ${package};
 
+import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelException;
 import org.apache.camel.Endpoint;
-import org.apache.camel.impl.DefaultComponent;
+import org.apache.camel.impl.UriEndpointComponent;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.util.IntrospectionSupport;
+
+import ${package}.internal.${name}ApiCollection;
+import ${package}.internal.${name}ApiName;
 
 /**
  * Represents the component that manages {@link ${name}Endpoint}.
  */
-public class ${name}Component extends DefaultComponent {
+@UriEndpoint(scheme = "${scheme}", consumerClass = ${name}Consumer.class, consumerPrefix = "consumer")
+public class ${name}Component extends UriEndpointComponent {
+
+    @UriParam
+    private ${name}Configuration configuration;
+
+    private final ${name}ApiCollection collection = ${name}ApiCollection.getCollection();
+
+    public ${name}Component(Class<? extends Endpoint> endpointClass) {
+        super(endpointClass);
+    }
+
+    public ${name}Component(CamelContext context, Class<? extends Endpoint> endpointClass) {
+        super(context, endpointClass);
+    }
 
     protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
-        Endpoint endpoint = new ${name}Endpoint(uri, this);
+        // split remaining path to get API name and method
+        final String[] pathElements = remaining.split("/");
+        String apiNameStr;
+        String methodName;
+        switch (pathElements.length) {
+            case 1:
+                apiNameStr = "";
+                methodName = pathElements[0];
+                break;
+            case 2:
+                apiNameStr = pathElements[0];
+                methodName = pathElements[1];
+                break;
+            default:
+                throw new CamelException("Invalid URI path [" + remaining +
+                "], must be of the format " + collection.getApiNames() + "/<operation-apiName>");
+        }
+        // get API enum from apiName string
+        final ${name}ApiName apiName;
+        try {
+            apiName = ${name}ApiName.fromValue(apiNameStr);
+        } catch (IllegalArgumentException e) {
+            throw new CamelException("Invalid URI path [" + apiNameStr +
+                "], must be one of " + collection.getApiNames());
+        }
+
+        final ${name}Configuration endpointConfiguration = createEndpointConfiguration(apiName);
+        final Endpoint endpoint = new ${name}Endpoint(uri, this, apiName, methodName, endpointConfiguration);
+
+        // set endpoint property inBody
         setProperties(endpoint, parameters);
         return endpoint;
     }
+
+    private ${name}Configuration createEndpointConfiguration(${name}ApiName name) throws Exception {
+        final Map<String, Object> componentProperties = new HashMap<String, Object>();
+        IntrospectionSupport.getProperties(configuration, componentProperties, null, false);
+
+        // create endpoint configuration with component properties
+        final ${name}Configuration endpointConfiguration = collection.getEndpointConfiguration(name);
+        IntrospectionSupport.setProperties(endpointConfiguration, componentProperties);
+        return endpointConfiguration;
+    }
+
+    public ${name}Configuration getConfiguration() {
+        return configuration;
+    }
+
+    public void setConfiguration(${name}Configuration configuration) {
+        this.configuration = configuration;
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/911e5413/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Configuration.java
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Configuration.java b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Configuration.java
new file mode 100644
index 0000000..ce8e9c4
--- /dev/null
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Configuration.java
@@ -0,0 +1,28 @@
+## ------------------------------------------------------------------------
+## 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 ${package};
+
+import org.apache.camel.spi.UriParams;
+
+/**
+ * Component configuration for ${name} component.
+ */
+@UriParams
+public class ${name}Configuration {
+
+    // TODO add component configuration properties
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/911e5413/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Consumer.java
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Consumer.java b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Consumer.java
index 340fb68..db8201d 100644
--- a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Consumer.java
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Consumer.java
@@ -16,36 +16,125 @@
 ## ------------------------------------------------------------------------
 package ${package};
 
-import java.util.Date;
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.impl.ScheduledPollConsumer;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.component.ApiMethod;
+import org.apache.camel.util.component.ApiMethodHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ${package}.internal.${name}PropertiesHelper;
 
 /**
  * The ${name} consumer.
  */
 public class ${name}Consumer extends ScheduledPollConsumer {
 
+    private static final Logger LOG = LoggerFactory.getLogger(${name}Consumer.class);
+
     private final ${name}Endpoint endpoint;
 
+    // helpers
+    private final ${name}PropertiesHelper propertiesHelper;
+    private final ApiMethodHelper methodHelper;
+
+    // API method to invoke
+    private final Enum<? extends ApiMethod> method;
+
+    // properties used to invoke
+    private final Map<String, Object> endpointProperties;
+
     public ${name}Consumer(${name}Endpoint endpoint, Processor processor) {
         super(endpoint, processor);
+
+        // cache variables
         this.endpoint = endpoint;
+        this.propertiesHelper = ${name}PropertiesHelper.getHelper();
+        this.methodHelper = endpoint.getMethodHelper();
+
+        // determine the consumer method to invoke
+        this.method = findMethod();
+
+        // get endpoint properties in a map
+        final HashMap<String, Object> properties = new HashMap<String, Object>();
+        propertiesHelper.getEndpointProperties(endpoint.getConfiguration(), properties);
+        this.endpointProperties = Collections.unmodifiableMap(properties);
+    }
+
+    @Override
+    public boolean isGreedy() {
+        // make this consumer not greedy to avoid making too many ${name} calls
+        return false;
+    }
+
+    private Enum<? extends ApiMethod> findMethod() {
+
+        Enum<? extends ApiMethod> result;
+        // find one that takes the largest subset of endpoint parameters
+        final Set<String> argNames = new HashSet<String>();
+        argNames.addAll(propertiesHelper.getEndpointPropertyNames(endpoint.getConfiguration()));
+
+        final String[] argNamesArray = argNames.toArray(new String[argNames.size()]);
+        List<Enum<? extends ApiMethod>> filteredMethods = methodHelper.filterMethods(
+                endpoint.getCandidates(), ApiMethodHelper.MatchType.SUPER_SET, argNamesArray);
+
+        if (filteredMethods.isEmpty()) {
+            throw new IllegalArgumentException(
+                    String.format("Missing properties for %s/%s, need one or more from %s",
+                            endpoint.getApiName().getName(), endpoint.getMethodName(),
+                            methodHelper.getMissingProperties(endpoint.getMethodName(), argNames)));
+        } else if (filteredMethods.size() == 1) {
+            // single match
+            result = filteredMethods.get(0);
+        } else {
+            result = methodHelper.getHighestPriorityMethod(filteredMethods);
+            LOG.warn("Using highest priority operation {} from operations {}", method, filteredMethods);
+        }
+        return result;
     }
 
     @Override
     protected int poll() throws Exception {
-        Exchange exchange = endpoint.createExchange();
+        // invoke the consumer method
+        final Map<String, Object> args = getMethodArguments();
+        try {
+            Object result = methodHelper.invokeMethod(endpoint.getApiProxy(), method, args);
 
-        // create a message body
-        Date now = new Date();
-        exchange.getIn().setBody("Hello World! The time is " + now);
+            // process result according to type
+            if (result != null && (result instanceof Collection || result.getClass().isArray())) {
+                // create an exchange for every element
+                final Object array = getResultAsArray(result);
+                final int length = Array.getLength(array);
+                for (int i = 0; i < length; i++) {
+                    processResult(Array.get(array, i));
+                }
+                return length;
+            } else {
+                processResult(result);
+                return 1; // number of messages polled
+            }
+        } catch (Throwable t) {
+            throw ObjectHelper.wrapRuntimeCamelException(t);
+        }
+    }
 
+    private void processResult(Object result) throws Exception {
+        Exchange exchange = getEndpoint().createExchange();
+        exchange.getIn().setBody(result);
         try {
             // send message to next processor in the route
             getProcessor().process(exchange);
-            return 1; // number of messages polled
         } finally {
             // log exception if an exception occurred and was not handled
             if (exchange.getException() != null) {
@@ -53,4 +142,22 @@ public class ${name}Consumer extends ScheduledPollConsumer {
             }
         }
     }
+
+    private Object getResultAsArray(Object result) {
+        if (result.getClass().isArray()) {
+            // no conversion needed
+            return result;
+        }
+        // must be a Collection
+        Collection<?> collection = (Collection<?>) result;
+        return collection.toArray(new Object[collection.size()]);
+    }
+
+    private Map<String, Object> getMethodArguments() {
+        Map<String, Object> arguments = new HashMap<String, Object>();
+        arguments.putAll(endpointProperties);
+
+        // TODO do consumer specific argument manipulation, such as setting constants or per poll properties
+        return arguments;
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/911e5413/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java
index 9c25c8e..73b87a6 100644
--- a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java
@@ -16,25 +16,73 @@
 ## ------------------------------------------------------------------------
 package ${package};
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.util.EndpointHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.component.ApiMethod;
+import org.apache.camel.util.component.ApiMethodHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ${package}.internal.${name}ApiCollection;
+import ${package}.internal.${name}ApiName;
+import ${package}.internal.${name}PropertiesHelper;
 
 /**
  * Represents a ${name} endpoint.
  */
+@UriEndpoint(scheme = "${scheme}", consumerClass = ${name}Consumer.class, consumerPrefix = "consumer")
 public class ${name}Endpoint extends DefaultEndpoint {
 
-    public ${name}Endpoint() {
-    }
+    private static final Logger LOG = LoggerFactory.getLogger(${name}Endpoint.class);
+
+    @UriParam
+    private final ${name}Configuration configuration;
+
+    // property name for Exchange 'In' message body
+    @UriParam
+    private String inBody;
+
+    // API name
+    private final ${name}ApiName apiName;
 
-    public ${name}Endpoint(String uri, ${name}Component component) {
+    // API method name
+    private final String methodName;
+
+    // API method helper
+    private final ApiMethodHelper methodHelper;
+
+    // candidate methods based on method name and endpoint configuration
+    private List<Enum<? extends ApiMethod>> candidates;
+
+    // TODO create and manage API proxies
+    private final Map<${name}ApiName, Object> proxyCache;
+
+    public ${name}Endpoint(String uri, ${name}Component component, ${name}ApiName apiName, String methodName, ${name}Configuration endpointConfiguration) {
         super(uri, component);
-    }
+        this.apiName = apiName;
+        this.methodName = methodName;
+        this.configuration = endpointConfiguration;
 
-    public ${name}Endpoint(String endpointUri) {
-        super(endpointUri);
+        methodHelper = ${name}ApiCollection.getCollection().getHelper(apiName);
+
+        // TODO manage API proxies
+        proxyCache = new HashMap<${name}ApiName, Object>();
+        proxyCache.put(${name}ApiName.HELLO1, new ${name}FileSigApi());
+        proxyCache.put(${name}ApiName.HELLO2, new ${name}JavadocSigApi());
     }
 
     public Producer createProducer() throws Exception {
@@ -42,10 +90,108 @@ public class ${name}Endpoint extends DefaultEndpoint {
     }
 
     public Consumer createConsumer(Processor processor) throws Exception {
-        return new ${name}Consumer(this, processor);
+        // make sure inBody is not set for consumers
+        if (inBody != null) {
+            throw new IllegalArgumentException("Option inBody is not supported for consumer endpoint");
+        }
+        final ${name}Consumer consumer = new ${name}Consumer(this, processor);
+        // also set consumer.* properties
+        configureConsumer(consumer);
+        return consumer;
     }
 
     public boolean isSingleton() {
         return true;
     }
+
+    @Override
+    public void configureProperties(Map<String, Object> options) {
+        super.configureProperties(options);
+
+        // set configuration properties first
+        try {
+            EndpointHelper.setReferenceProperties(getCamelContext(), configuration, options);
+            EndpointHelper.setProperties(getCamelContext(), configuration, options);
+        } catch (Exception e) {
+            throw new IllegalArgumentException(e.getMessage(), e);
+        }
+
+        // validate and initialize state
+        initState();
+    }
+
+    private void initState() {
+
+        // get endpoint property names
+        final Set<String> arguments = new HashSet<String>();
+        arguments.addAll(${name}PropertiesHelper.getHelper().getEndpointPropertyNames(configuration));
+
+        // add inBody argument for producers
+        if (inBody != null) {
+            arguments.add(inBody);
+        }
+        final String[] argNames = arguments.toArray(new String[arguments.size()]);
+
+        // create a list of candidate methods
+        candidates = new ArrayList<Enum<? extends ApiMethod>>();
+        candidates.addAll(methodHelper.getCandidateMethods(methodName, argNames));
+
+        // error if there are no candidates
+        if (candidates.isEmpty()) {
+            throw new IllegalArgumentException(
+                    String.format("No matching method for %s/%s, with arguments %s",
+                            apiName.getName(), methodName, arguments));
+        }
+
+        // log missing/extra properties for debugging
+        if (LOG.isDebugEnabled()) {
+            final Set<String> missing = methodHelper.getMissingProperties(methodName, arguments);
+            if (!missing.isEmpty()) {
+                LOG.debug("Method {} could use one or more properties from {}", methodName, missing);
+            }
+        }
+    }
+
+    @Override
+    public ${name}Component getComponent() {
+        return (${name}Component) super.getComponent();
+    }
+
+    public ${name}Configuration getConfiguration() {
+        return configuration;
+    }
+
+    public ${name}ApiName getApiName() {
+        return apiName;
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    public ApiMethodHelper getMethodHelper() {
+        return methodHelper;
+    }
+
+    public List<Enum<? extends ApiMethod>> getCandidates() {
+        return Collections.unmodifiableList(candidates);
+    }
+
+    public String getInBody() {
+        return inBody;
+    }
+
+    public void setInBody(String inBody) {
+        // validate property name
+        ObjectHelper.notNull(inBody, "inBody");
+        if (!${name}PropertiesHelper.getHelper().getValidEndpointProperties(configuration).contains(inBody)) {
+            throw new IllegalArgumentException("Unknown property " + inBody);
+        }
+        this.inBody = inBody;
+    }
+
+    public Object getApiProxy() {
+        // TODO manage API proxies
+        return proxyCache.get(apiName);
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/911e5413/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Producer.java
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Producer.java b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Producer.java
index 3fd064a..ece4283 100644
--- a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Producer.java
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Producer.java
@@ -16,25 +16,170 @@
 ## ------------------------------------------------------------------------
 package ${package};
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
-import org.apache.camel.impl.DefaultProducer;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.impl.DefaultAsyncProducer;
+import org.apache.camel.spi.ExecutorServiceManager;
+import org.apache.camel.spi.ThreadPoolProfile;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.component.ApiMethod;
+import org.apache.camel.util.component.ApiMethodHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import ${package}.internal.${name}Constants;
+import ${package}.internal.${name}PropertiesHelper;
+
 /**
  * The ${name} producer.
  */
-public class ${name}Producer extends DefaultProducer {
-    private static final Logger LOG = LoggerFactory.getLogger(${name}Producer.class);
+public class ${name}Producer extends DefaultAsyncProducer {
+    private static final transient Logger LOG = LoggerFactory.getLogger(${name}Producer.class);
+
+    // thread pool executor
+    private static ExecutorService executorService;
+
     private ${name}Endpoint endpoint;
 
+    private final ${name}PropertiesHelper propertiesHelper;
+    private final ApiMethodHelper methodHelper;
+
     public ${name}Producer(${name}Endpoint endpoint) {
         super(endpoint);
         this.endpoint = endpoint;
+
+        // cache helpers
+        this.propertiesHelper = ${name}PropertiesHelper.getHelper();
+        this.methodHelper = endpoint.getMethodHelper();
     }
 
-    public void process(Exchange exchange) throws Exception {
-        System.out.println(exchange.getIn().getBody());    
+    @Override
+    public boolean process(final Exchange exchange, final AsyncCallback callback) {
+        // properties for method arguments
+        final Map<String, Object> properties = new HashMap<String, Object>();
+        propertiesHelper.getEndpointProperties(endpoint.getConfiguration(), properties);
+        propertiesHelper.getExchangeProperties(exchange, properties);
+
+        // decide which method to invoke
+        final Enum<? extends ApiMethod> method = findMethod(exchange, properties);
+        if (method == null) {
+            // synchronous failure
+            callback.done(true);
+            return true;
+        }
+
+        // create a runnable invocation task to be submitted on a background thread pool
+        // this way we avoid blocking the current thread for long running methods
+        Runnable invocation = new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("Invoking operation {} with {}", ((ApiMethod)method).getName(), properties.keySet());
+                    }
+
+                    // also check whether we need to get Raw JSON
+                    Object result = methodHelper.invokeMethod(endpoint.getApiProxy(), method, properties);
+
+                    // producer returns a single response, even for methods with List return types
+                    exchange.getOut().setBody(result);
+                    // copy headers
+                    exchange.getOut().setHeaders(exchange.getIn().getHeaders());
+
+                } catch (Throwable t) {
+                    exchange.setException(ObjectHelper.wrapRuntimeCamelException(t));
+                } finally {
+                    callback.done(false);
+                }
+            }
+        };
+
+        getExecutorService(getEndpoint().getCamelContext()).submit(invocation);
+        return false;
+    }
+
+    private Enum<? extends ApiMethod> findMethod(Exchange exchange, Map<String, Object> properties) {
+
+        Enum<? extends ApiMethod> method = null;
+        final List<Enum<? extends ApiMethod>> candidates = endpoint.getCandidates();
+        if (processInBody(exchange, properties)) {
+
+            // filter candidates based on endpoint and exchange properties
+            final Set<String> argNames = properties.keySet();
+            final List<Enum<? extends ApiMethod>> filteredMethods = methodHelper.filterMethods(candidates,
+                    ApiMethodHelper.MatchType.SUPER_SET,
+                    argNames.toArray(new String[argNames.size()]));
+
+            // get the method to call
+            if (filteredMethods.isEmpty()) {
+                final Set<String> missing = methodHelper.getMissingProperties(endpoint.getMethodName(), argNames);
+                throw new RuntimeCamelException(String.format("Missing properties for %s, need one or more from %s",
+                        endpoint.getMethodName(), missing));
+            } else if (filteredMethods.size() == 1) {
+                // found an exact match
+                method = filteredMethods.get(0);
+            } else {
+                method = methodHelper.getHighestPriorityMethod(filteredMethods);
+                LOG.warn("Calling highest priority operation {} from operations {}", method, filteredMethods);
+            }
+        }
+
+        return method;
+    }
+
+    // returns false on exception, which is set in exchange
+    private boolean processInBody(Exchange exchange, Map<String, Object> properties) {
+        final String inBodyProperty = endpoint.getInBody();
+        if (inBodyProperty != null) {
+
+            Object value = exchange.getIn().getBody();
+            try {
+                value = getEndpoint().getCamelContext().getTypeConverter().mandatoryConvertTo(
+                        endpoint.getConfiguration().getClass().getDeclaredField(inBodyProperty).getType(),
+                        exchange, value);
+            } catch (Exception e) {
+                exchange.setException(new RuntimeCamelException(String.format(
+                        "Error converting value %s to property %s: %s", value, inBodyProperty, e.getMessage()), e));
+
+                return false;
+            }
+
+            LOG.debug("Property [{}] has message body value {}", inBodyProperty, value);
+            properties.put(inBodyProperty, value);
+        }
+
+        return true;
+    }
+
+    protected static synchronized ExecutorService getExecutorService(CamelContext context) {
+        // CamelContext will shutdown thread pool when it shutdown so we can
+        // lazy create it on demand
+        // but in case of hot-deploy or the likes we need to be able to
+        // re-create it (its a shared static instance)
+        if (executorService == null || executorService.isTerminated() || executorService.isShutdown()) {
+            final ExecutorServiceManager manager = context.getExecutorServiceManager();
+
+            // try to lookup a pool first based on profile
+            ThreadPoolProfile poolProfile = manager.getThreadPoolProfile(
+                    ${name}Constants.THREAD_PROFILE_NAME);
+            if (poolProfile == null) {
+                poolProfile = manager.getDefaultThreadPoolProfile();
+            }
+
+            // create a new pool using the custom or default profile
+            executorService = manager.newScheduledThreadPool(${name}Producer.class,
+                    ${name}Constants.THREAD_PROFILE_NAME, poolProfile);
+        }
+
+        return executorService;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/911e5413/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/internal/__name__Constants.java
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/internal/__name__Constants.java b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/internal/__name__Constants.java
new file mode 100644
index 0000000..90e0f1a
--- /dev/null
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/internal/__name__Constants.java
@@ -0,0 +1,29 @@
+## ------------------------------------------------------------------------
+## 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 ${package}.internal;
+
+/**
+ * Constants for ${name} component.
+ */
+public interface ${name}Constants {
+
+    // suffix for parameters when passed as exchange header properties
+    String PROPERTY_PREFIX = "Camel${name}.";
+
+    // thread profile name for this component
+    String THREAD_PROFILE_NAME = "Camel${name}";
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/911e5413/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/internal/__name__PropertiesHelper.java
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/internal/__name__PropertiesHelper.java b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/internal/__name__PropertiesHelper.java
new file mode 100644
index 0000000..fe6910c
--- /dev/null
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/internal/__name__PropertiesHelper.java
@@ -0,0 +1,40 @@
+## ------------------------------------------------------------------------
+## 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 ${package}.internal;
+
+import org.apache.camel.util.component.ApiMethodPropertiesHelper;
+
+import ${package}.${name}Configuration;
+
+/**
+ * Singleton {@link ApiMethodPropertiesHelper} for ${name} component.
+ */
+public final class ${name}PropertiesHelper extends ApiMethodPropertiesHelper<${name}Configuration> {
+
+    private static ${name}PropertiesHelper helper;
+
+    private ${name}PropertiesHelper() {
+        super(${name}Configuration.class, ${name}Constants.PROPERTY_PREFIX);
+    }
+
+    public static synchronized ${name}PropertiesHelper getHelper() {
+        if (helper == null) {
+            helper = new ${name}PropertiesHelper();
+        }
+        return helper;
+    }
+}