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;
+ }
+}