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/12 05:45:44 UTC

[2/2] git commit: Refactored API Endpoint, Consumer and Producer to extrac Abstract classes in camel-core, simplifying generated code, minor fixes in route test template, added two parameter method in sample API

Refactored API Endpoint, Consumer and Producer to extrac Abstract classes in camel-core, simplifying generated code, minor fixes in route test template, added two parameter method in sample API


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

Branch: refs/heads/master
Commit: 37541d2e31ce640f77298c599bc050bc80166902
Parents: cc4e778
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Wed Jun 11 16:12:50 2014 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Wed Jun 11 20:10:21 2014 -0700

----------------------------------------------------------------------
 .../util/component/AbstractApiConsumer.java     | 200 +++++++++++++++++
 .../util/component/AbstractApiEndpoint.java     | 217 ++++++++++++++++++
 .../util/component/AbstractApiProducer.java     | 224 +++++++++++++++++++
 .../src/main/java/__name__FileHello.java        |   4 +
 .../src/main/java/__name__JavadocHello.java     |   4 +
 .../signatures/file-sig-api.txt                 |   1 +
 .../src/main/java/__name__Component.java        |  27 +--
 .../src/main/java/__name__Consumer.java         | 136 +----------
 .../src/main/java/__name__Endpoint.java         | 150 ++-----------
 .../src/main/java/__name__Producer.java         | 159 +------------
 .../src/main/resources/api-collection.vm        |   2 +-
 .../src/main/resources/api-route-test.vm        |   5 +-
 12 files changed, 697 insertions(+), 432 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/37541d2e/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiConsumer.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiConsumer.java b/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiConsumer.java
new file mode 100644
index 0000000..9406f35
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiConsumer.java
@@ -0,0 +1,200 @@
+/**
+ * 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.util.component;
+
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract base class for API Component Consumers.
+ */
+public abstract class AbstractApiConsumer extends ScheduledPollConsumer {
+
+    // logger
+    protected final Logger log = LoggerFactory.getLogger(getClass());
+
+    // API Endpoint
+    protected final AbstractApiEndpoint endpoint;
+
+    // helpers
+    protected final ApiMethodPropertiesHelper propertiesHelper;
+    protected final ApiMethodHelper methodHelper;
+
+    // API method to invoke
+    protected final Enum<? extends ApiMethod> method;
+
+    // properties used to invoke
+    protected final Map<String, Object> endpointProperties;
+
+    public AbstractApiConsumer(AbstractApiEndpoint endpoint, Processor processor) {
+        super(endpoint, processor);
+
+        this.endpoint = endpoint;
+
+        // cache helpers
+        this.methodHelper = endpoint.getMethodHelper();
+        this.propertiesHelper = endpoint.getPropertiesHelper();
+
+        // 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);
+
+        this.method = findMethod();
+    }
+
+    @Override
+    public boolean isGreedy() {
+        // make this consumer not greedy to avoid making too many calls
+        return false;
+    }
+
+    @SuppressWarnings("unchecked")
+    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()));
+
+        interceptArgumentNames(argNames);
+
+        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;
+    }
+
+    /**
+     * Intercept argument names used to find consumer method.
+     * Used to add any custom/hidden method arguments, which MUST be provided in getMethodArguments() override.
+     * @param argNames argument names.
+     */
+    protected void interceptArgumentNames(Set<String> argNames) {
+        // do nothing by default
+    }
+
+    @Override
+    protected int poll() throws Exception {
+        // invoke the consumer method
+        final Map<String, Object> args = getMethodArguments();
+        try {
+            Object result = doInvokeMethod(args);
+
+            // 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);
+        }
+    }
+
+    /**
+     * Invoke the API method.
+     * This method can be overridden, for example to synchronize API calls for thread-unsafe proxies.
+     * Derived class MUST call super.doInvokeMethod() to invoke the API method.
+     * @param args method arguments from endpoint parameters.
+     * @return method invocation result.
+     */
+    @SuppressWarnings("unchecked")
+    protected Object doInvokeMethod(Map<String, Object> args) {
+        return methodHelper.invokeMethod(endpoint.getApiProxy(), method, args);
+    }
+
+    private void processResult(Object result) throws Exception {
+        Exchange exchange = getEndpoint().createExchange();
+        exchange.getIn().setBody(result);
+
+        doProcessResult(exchange);
+        try {
+            // send message to next processor in the route
+            getProcessor().process(exchange);
+        } finally {
+            // log exception if an exception occurred and was not handled
+            final Exception exception = exchange.getException();
+            if (exception != null) {
+                getExceptionHandler().handleException("Error processing exchange", exchange, exception);
+            }
+        }
+    }
+
+    /**
+     * Derived classes can do additional result exchange processing, for example, adding custom headers.
+     * @param resultExchange result as a Camel exchange.
+     */
+    protected void doProcessResult(Exchange resultExchange) {
+        // do nothing by default
+    }
+
+    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()]);
+    }
+
+    /**
+     * Return method arguments to use in doInvokeMethod().
+     * Derived classes can override it to add custom arguments.
+     * Overriding method MUST first call super.getMethodArguments() to get endpoint properties.
+     * @return
+     */
+    protected Map<String, Object> getMethodArguments() {
+        Map<String, Object> arguments = new HashMap<String, Object>();
+        arguments.putAll(endpointProperties);
+        return arguments;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/37541d2e/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiEndpoint.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiEndpoint.java b/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiEndpoint.java
new file mode 100644
index 0000000..6d09251
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiEndpoint.java
@@ -0,0 +1,217 @@
+/**
+ * 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.util.component;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.Component;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.util.EndpointHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract base class for API Component Endpoints.
+ */
+public abstract class AbstractApiEndpoint extends DefaultEndpoint {
+
+    // logger
+    protected final Logger log = LoggerFactory.getLogger(getClass());
+
+    // API name
+    protected final ApiName apiName;
+
+    // API method name
+    protected final String methodName;
+
+    // API method helper
+    protected final ApiMethodHelper methodHelper;
+
+    // property name for Exchange 'In' message body
+    @UriParam
+    protected String inBody;
+
+    // candidate methods based on method name and endpoint configuration
+    private List<Enum<? extends ApiMethod>> candidates;
+
+    public AbstractApiEndpoint(String endpointUri, Component component,
+                               ApiName apiName, String methodName, ApiMethodHelper methodHelper) {
+        super(endpointUri, component);
+
+        this.apiName = apiName;
+        this.methodName = methodName;
+        this.methodHelper = methodHelper;
+    }
+
+    public boolean isSingleton() {
+        return true;
+    }
+
+    /**
+     * Returns generated helper that extends {@link ApiMethodPropertiesHelper} to work with API properties.
+     * @return properties helper.
+     */
+    protected abstract ApiMethodPropertiesHelper getPropertiesHelper();
+
+    @Override
+    public void configureProperties(Map<String, Object> options) {
+        super.configureProperties(options);
+
+        // set configuration properties first
+        try {
+            Object configuration = getConfiguration();
+            EndpointHelper.setReferenceProperties(getCamelContext(), configuration, options);
+            EndpointHelper.setProperties(getCamelContext(), configuration, options);
+        } catch (Exception e) {
+            throw new IllegalArgumentException(e.getMessage(), e);
+        }
+
+        // validate and initialize state
+        initState();
+
+        afterConfigureProperties();
+    }
+
+    /**
+     * Initialize proxies, create server connections, etc. after endpoint properties have been configured.
+     */
+    protected abstract void afterConfigureProperties();
+
+    /**
+     * Initialize endpoint state, including endpoint arguments, find candidate methods, etc.
+     */
+    @SuppressWarnings("unchecked")
+    protected void initState() {
+
+        // get endpoint property names
+        final Set<String> arguments = new HashSet<String>();
+        arguments.addAll(getPropertiesHelper().getEndpointPropertyNames(getConfiguration()));
+
+        interceptEndpointArguments(arguments);
+
+        // 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);
+            }
+        }
+    }
+
+    /**
+     * Intercept initial endpoint arguments to add custom/hidden arguments for method calls, etc.
+     * @param arguments
+     */
+    @SuppressWarnings("unused")
+    protected void interceptEndpointArguments(Set<String> arguments) {
+        // do nothing by default
+    }
+
+    /**
+     * Returns endpoint configuration object.
+     * One of the generated *EndpointConfiguration classes that extends component configuration class.
+     * @return
+     */
+    public abstract Object getConfiguration();
+
+    /**
+     * Returns API name.
+     * @return apiName property.
+     */
+    public ApiName getApiName() {
+        return apiName;
+    }
+
+    /**
+     * Returns method name.
+     * @return methodName property.
+     */
+    public String getMethodName() {
+        return methodName;
+    }
+
+    /**
+     * Returns method helper.
+     * @return methodHelper property.
+     */
+    public ApiMethodHelper getMethodHelper() {
+        return methodHelper;
+    }
+
+    /**
+     * Returns candidate methods for this endpoint.
+     * @return list of candidate methods.
+     */
+    public List<Enum<? extends ApiMethod>> getCandidates() {
+        return Collections.unmodifiableList(candidates);
+    }
+
+    /**
+     * Returns name of parameter passed in the exchange In Body.
+     * @return inBody property.
+     */
+    public String getInBody() {
+        return inBody;
+    }
+
+    /**
+     * Sets the name of a parameter to be passed in the exchange In Body.
+     * @param inBody parameter name
+     * @throws IllegalArgumentException for invalid parameter name.
+     */
+    public void setInBody(String inBody) throws IllegalArgumentException {
+        // validate property name
+        ObjectHelper.notNull(inBody, "inBody");
+        if (!getPropertiesHelper().getValidEndpointProperties(getConfiguration()).contains(inBody)) {
+            throw new IllegalArgumentException("Unknown property " + inBody);
+        }
+        this.inBody = inBody;
+    }
+
+    /**
+     * Returns an instance of an API Proxy based on apiName.
+     * Called by {@link AbstractApiConsumer} or {@link AbstractApiProducer}.
+     * @return a Java object that implements the method to be invoked.
+     * @see AbstractApiProducer
+     * @see AbstractApiConsumer
+     */
+    public abstract Object getApiProxy();
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/37541d2e/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java b/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java
new file mode 100644
index 0000000..817c63b
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java
@@ -0,0 +1,224 @@
+/**
+ * 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.util.component;
+
+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.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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base class for API based Producers
+ */
+public abstract class AbstractApiProducer extends DefaultAsyncProducer {
+
+    // thread pool executor
+    protected static ExecutorService executorService;
+
+    // API Endpoint
+    protected final AbstractApiEndpoint endpoint;
+
+    // properties helper
+    protected final ApiMethodPropertiesHelper propertiesHelper;
+
+    // method helper
+    protected final ApiMethodHelper methodHelper;
+
+    // logger
+    private final transient Logger log = LoggerFactory.getLogger(getClass());
+
+    public AbstractApiProducer(AbstractApiEndpoint endpoint, ApiMethodPropertiesHelper propertiesHelper) {
+        super(endpoint);
+        this.propertiesHelper = propertiesHelper;
+        this.endpoint = endpoint;
+        this.methodHelper = endpoint.getMethodHelper();
+    }
+
+    @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);
+
+        interceptProperties(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());
+                    }
+
+                    Object result = doInvokeMethod(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());
+
+                    doProcessResult(exchange);
+
+                } catch (Throwable t) {
+                    exchange.setException(ObjectHelper.wrapRuntimeCamelException(t));
+                } finally {
+                    callback.done(false);
+                }
+            }
+        };
+
+        getExecutorService(getEndpoint().getCamelContext()).submit(invocation);
+        return false;
+    }
+
+    /**
+     * Intercept method invocation arguments used to find and invoke API method.
+     * Can be overridden to add custom method properties.
+     * @param properties method invocation arguments.
+     */
+    @SuppressWarnings("unused")
+    protected void interceptProperties(Map<String, Object> properties) {
+        // do nothing by default
+    }
+
+    /**
+     * Invoke the API method. Derived classes can override, but MUST call super.doInvokeMethod().
+     * @param method API method to invoke.
+     * @param properties method arguments from endpoint properties and exchange In headers.
+     * @return API method invocation result.
+     * @throws RuntimeCamelException on error. Exceptions thrown by API method are wrapped.
+     */
+    @SuppressWarnings("unchecked")
+    protected Object doInvokeMethod(Enum<? extends ApiMethod> method, Map<String, Object> properties) throws RuntimeCamelException {
+        return methodHelper.invokeMethod(endpoint.getApiProxy(), method, properties);
+    }
+
+    /**
+     * Do additional result processing, for example, add custom headers, etc.
+     * @param resultExchange API method result as exchange.
+     */
+    protected void doProcessResult(Exchange resultExchange) {
+        // do nothing by default
+    }
+
+    @SuppressWarnings("unchecked")
+    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;
+    }
+
+    private 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
+            final String threadProfileName = getThreadProfileName();
+            ThreadPoolProfile poolProfile = manager.getThreadPoolProfile(
+                    threadProfileName);
+            if (poolProfile == null) {
+                poolProfile = manager.getDefaultThreadPoolProfile();
+            }
+
+            // create a new pool using the custom or default profile
+            executorService = manager.newScheduledThreadPool(getClass(),
+                    threadProfileName, poolProfile);
+        }
+
+        return executorService;
+    }
+
+    /**
+     * Returns Thread profile name. Generated as a constant THREAD_PROFILE_NAME in *Constants.
+     * @return thread profile name to use.
+     */
+    protected abstract String getThreadProfileName();
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/37541d2e/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/src/main/java/__name__FileHello.java
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/src/main/java/__name__FileHello.java b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/src/main/java/__name__FileHello.java
index fb9bc52..071e281 100644
--- a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/src/main/java/__name__FileHello.java
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/src/main/java/__name__FileHello.java
@@ -28,4 +28,8 @@ public class ${name}FileHello {
     public String greetMe(String name) {
         return "Hello " + name;
     }
+
+    public String greetUs(String name1, String name2) {
+            return "Hello " + name1 + ", " + name2;
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/37541d2e/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/src/main/java/__name__JavadocHello.java
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/src/main/java/__name__JavadocHello.java b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/src/main/java/__name__JavadocHello.java
index 72e55ca..39430f2 100644
--- a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/src/main/java/__name__JavadocHello.java
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-api/src/main/java/__name__JavadocHello.java
@@ -28,4 +28,8 @@ public class ${name}JavadocHello {
     public String greetMe(String name) {
         return "Hello " + name;
     }
+
+    public String greetUs(String name1, String name2) {
+            return "Hello " + name1 + ", " + name2;
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/37541d2e/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/signatures/file-sig-api.txt
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/signatures/file-sig-api.txt b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/signatures/file-sig-api.txt
index f9c1310..e7073a0 100644
--- a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/signatures/file-sig-api.txt
+++ b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/signatures/file-sig-api.txt
@@ -1,2 +1,3 @@
 public String sayHi();
 public String greetMe(String name);
+public String greetUs(String name1, String name2);

http://git-wip-us.apache.org/repos/asf/camel/blob/37541d2e/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 6694b4e..34ce74c 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
@@ -55,25 +55,26 @@ public class ${name}Component extends UriEndpointComponent {
         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>");
+        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-name>");
         }
+
         // 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 prefix [" + remaining +
-                "], must be one of " + collection.getApiNames());
+            throw new CamelException("Invalid URI path prefix [" + remaining
+                + "], must be one of " + collection.getApiNames());
         }
 
         final ${name}Configuration endpointConfiguration = createEndpointConfiguration(apiName);

http://git-wip-us.apache.org/repos/asf/camel/blob/37541d2e/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 db8201d..56ae89d 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,148 +16,16 @@
 ## ------------------------------------------------------------------------
 package ${package};
 
-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;
+import org.apache.camel.util.component.AbstractApiConsumer;
 
 /**
  * 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 class ${name}Consumer extends AbstractApiConsumer {
 
     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 {
-        // invoke the consumer method
-        final Map<String, Object> args = getMethodArguments();
-        try {
-            Object result = methodHelper.invokeMethod(endpoint.getApiProxy(), method, args);
-
-            // 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);
-        } finally {
-            // log exception if an exception occurred and was not handled
-            if (exchange.getException() != null) {
-                getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
-            }
-        }
-    }
-
-    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/37541d2e/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 84917b3..3b68f84 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,26 +16,13 @@
 ## ------------------------------------------------------------------------
 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 org.apache.camel.util.component.AbstractApiEndpoint;
+import org.apache.camel.util.component.ApiMethodPropertiesHelper;
 
 import ${package}.internal.${name}ApiCollection;
 import ${package}.internal.${name}ApiName;
@@ -45,44 +32,19 @@ import ${package}.internal.${name}PropertiesHelper;
  * Represents a ${name} endpoint.
  */
 @UriEndpoint(scheme = "${scheme}", consumerClass = ${name}Consumer.class, consumerPrefix = "consumer")
-public class ${name}Endpoint extends DefaultEndpoint {
-
-    private static final Logger LOG = LoggerFactory.getLogger(${name}Endpoint.class);
+public class ${name}Endpoint extends AbstractApiEndpoint {
 
     @UriParam
-    private final ${name}Configuration configuration;
-
-    // property name for Exchange 'In' message body
-    @UriParam
-    private String inBody;
-
-    // API name
-    private final ${name}ApiName apiName;
+    protected final ${name}Configuration configuration;
 
-    // API method name
-    private final String methodName;
+    // TODO create and manage API proxy
+    private Object apiProxy;
 
-    // API method helper
-    private final ApiMethodHelper methodHelper;
+    public ${name}Endpoint(String uri, ${name}Component component,
+                         ${name}ApiName apiName, String methodName, ${name}Configuration endpointConfiguration) {
+        super(uri, component, apiName, methodName, ${name}ApiCollection.getCollection().getHelper(apiName));
 
-    // 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;
-
-        methodHelper = ${name}ApiCollection.getCollection().getHelper(apiName);
-
-        // TODO manage API proxies
-        proxyCache = new HashMap<${name}ApiName, Object>();
-        proxyCache.put(${name}ApiName.HELLO_FILE, new ${name}FileHello());
-        proxyCache.put(${name}ApiName.HELLO_JAVADOC, new ${name}JavadocHello());
     }
 
     public Producer createProducer() throws Exception {
@@ -100,98 +62,30 @@ public class ${name}Endpoint extends DefaultEndpoint {
         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();
+    protected ApiMethodPropertiesHelper getPropertiesHelper() {
+        return ${name}PropertiesHelper.getHelper();
     }
 
-    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
+    protected void afterConfigureProperties() {
+        // TODO create API proxy, set connection properties, etc.
+        switch ((${name}ApiName) apiName) {
+            case HELLO_FILE:
+                apiProxy = new ${name}FileHello();
+                break;
+            case HELLO_JAVADOC:
+                apiProxy = new ${name}JavadocHello();
         }
     }
 
     @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;
-    }
-
+    @Override
     public Object getApiProxy() {
-        // TODO manage API proxies
-        return proxyCache.get(apiName);
+        return apiProxy;
     }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/37541d2e/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 ece4283..46c4871 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,24 +16,7 @@
 ## ------------------------------------------------------------------------
 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.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 org.apache.camel.util.component.AbstractApiProducer;
 
 import ${package}.internal.${name}Constants;
 import ${package}.internal.${name}PropertiesHelper;
@@ -41,145 +24,13 @@ import ${package}.internal.${name}PropertiesHelper;
 /**
  * The ${name} producer.
  */
-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 class ${name}Producer extends AbstractApiProducer {
 
     public ${name}Producer(${name}Endpoint endpoint) {
-        super(endpoint);
-        this.endpoint = endpoint;
-
-        // cache helpers
-        this.propertiesHelper = ${name}PropertiesHelper.getHelper();
-        this.methodHelper = endpoint.getMethodHelper();
+        super(endpoint, ${name}PropertiesHelper.getHelper());
     }
 
-    @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;
+    protected String getThreadProfileName() {
+        return ${name}Constants.THREAD_PROFILE_NAME;
     }
-
-    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/37541d2e/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm
index 0774366..1b73e7f 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm
@@ -21,8 +21,8 @@
  */
 package $packageName;
 
-import java.util.Map;
 import java.util.HashMap;
+import java.util.Map;
 
 #set( $componentConfig = "${componentName}Configuration" )
 import ${componentPackage}.${componentConfig};

http://git-wip-us.apache.org/repos/asf/camel/blob/37541d2e/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm
index a3acad1..bf71e7f 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm
@@ -22,6 +22,7 @@
 package $packageName;
 
 import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.test.junit4.CamelTestSupport;
@@ -58,7 +59,7 @@ public class ${testName} extends CamelTestSupport {
         // using $helper.getCanonicalName($argType) message body for single parameter "$args.get(0).Name"
 ## multiple arguments, pass them as headers
 #elseif ( $args.size() > 1 )
-        final HashMap<String, Object> headers = new HashMap<String, Object>();
+        final Map<String, Object> headers = new HashMap<String, Object>();
 #foreach ( $arg in $args )
 #if ( !$arg.Type.isPrimitive() )
         // parameter type is $helper.getCanonicalName($arg.Type)
@@ -77,7 +78,7 @@ template().requestBody("direct://${model.UniqueName}", (Object)null);
 ## typecast body to avoid requestBody() conflict
 template().requestBody("direct://${model.UniqueName}", (${helper.getCanonicalName($argType)}) $helper.getDefaultArgValue($argType));
 #else
-template().requestBodyAndHeader("direct://${model.UniqueName}", null, headers);
+template().requestBodyAndHeaders("direct://${model.UniqueName}", null, headers);
 #end
 #if ( !$voidResult )