Chapter 46. Getting Started with the Framework
Abstract
This chapter explains the basic principles of implementing a Camel component using the API component framework, based on code generated using the camel-archetype-api-component
Maven archetype.
46.1. Generate Code with the Maven Archetype
Maven archetypes
A Maven archetype is analogous to a code wizard: given a few simple parameters, it generates a complete, working Maven project, populated with sample code. You can then use this project as a template, customizing the implementation to create your own application.
The API component Maven archetype
The API component framework provides a Maven archetype, camel-archetype-api-component
, that can generate starting point code for your own API component implementation. This is the recommended approach to start creating your own API component.
Prerequisites
The only prerequisites for running the camel-archetype-api-component
archetype are that Apache Maven is installed and the Maven settings.xml
file is configured to use the standard Fuse repositories.
Invoke the Maven archetype
To create an Example
component, which uses the example
URI scheme, invoke the camel-archetype-api-component
archetype to generate a new Maven project, as follows:
mvn archetype:generate \ -DarchetypeGroupId=org.apache.camel.archetypes \ -DarchetypeArtifactId=camel-archetype-api-component \ -DarchetypeVersion=2.21.0.fuse-730078-redhat-00001 \ -DgroupId=org.jboss.fuse.example \ -DartifactId=camel-api-example \ -Dname=Example \ -Dscheme=example \ -Dversion=1.0-SNAPSHOT \ -DinteractiveMode=false
The backslash character, \
, at the end of each line represents line continuation, which works only on Linux and UNIX platforms. On Windows platforms, remove the backslash and put the arguments all on a single line.
Options
Options are provided to the archetype generation command using the syntax, -DName=Value
. Most of the options should be set as shown in the preceding mvn archetype:generate
command, but a few of the options can be modified, to customize the generated project. The following table shows the options that you can use to customize the generated API component project:
Name | Description |
---|---|
| (Generic Maven option) Specifies the group ID of the generated Maven project. By default, this value also defines the Java package name for the generated classes. Hence, it is a good idea to choose this value to match the Java package name that you want. |
| (Generic Maven option) Specifies the artifact ID of the generated Maven project. |
| The name of the API component. This value is used for generating class names in the generated code (hence, it is recommended that the name should start with a capital letter). |
| The default scheme to use in URIs for this component. You should make sure that this scheme does not conflict with the scheme of any existing Camel components. |
| (Generic Maven option) Ideally, this should be the Apache Camel version used by the container where you plan to deploy the component. If necessary, however, you can also modify the versions of Maven dependencies after you have generated the project. |
Structure of the generated project
Assuming that the code generation step completes successfully, you should see a new directory, camel-api-example
, which contains the new Maven project. If you look inside the camel-api-example
directory, you will see that it has the following general structure:
camel-api-example/ pom.xml camel-api-example-api/ camel-api-example-component/
At the top level of the project is an aggregate POM, pom.xml
, which is configured to build two sub-projects, as follows:
- camel-api-example-api
The API sub-project (named as
ArtifactId-api
) holds the Java API which you are about to turn into a component. If you are basing the API component on a Java API that you wrote yourself, you can put the Java API code directly into this project.The API sub-project can be used for one or more of the following purposes:
- To package up the Java API code (if it is not already available as a Maven package).
- To generate Javadoc for the Java API (providing the needed metadata for the API component framework).
- To generate the Java API code from an API description (for example, from a WADL description of a REST API).
In some cases, however, you might not need to perform any of these tasks. For example, if the API component is based on a third-party API, which already provides the Java API and Javadoc in a Maven package. In such cases, you can delete the API sub-project.
- camel-api-example-component
-
The component sub-project (named as
ArtifactId-component
) holds the implementation of the new API component. This includes the component implementation classes and the configuration of thecamel-api-component-maven
plug-in (which generates the API mapping classes from the Java API).
46.2. Generated API Sub-Project
Overview
Assuming that you generated a new Maven project as described in Section 46.1, “Generate Code with the Maven Archetype”, you can now find a Maven sub-project for packaging the Java API under the camel-api-example/camel-api-example-api
project directory. In this section, we take a closer look at the generated example code and describe how it works.
Sample Java API
The generated example code includes a sample Java API, on which the example API component is based. The sample Java API is relatively simple, consisting of just two Hello World classes: ExampleJavadocHello
and ExampleFileHello
.
ExampleJavadocHello class
Example 46.1, “ExampleJavadocHello class” shows the ExampleJavadocHello
class from the sample Java API. As the name of the class suggests, this particular class is used to show how you can supply mapping metadata from Javadoc.
Example 46.1. ExampleJavadocHello class
// Java package org.jboss.fuse.example.api; /** * Sample API used by Example Component whose method signatures are read from Javadoc. */ public class ExampleJavadocHello { public String sayHi() { return "Hello!"; } public String greetMe(String name) { return "Hello " + name; } public String greetUs(String name1, String name2) { return "Hello " + name1 + ", " + name2; } }
ExampleFileHello class
Example 46.2, “ExampleFileHello class” shows the ExampleFileHello
class from the sample Java API. As the name of the class suggests, this particular class is used to show how you can supply mapping metadata from a signature file.
Example 46.2. ExampleFileHello class
// Java package org.jboss.fuse.example.api; /** * Sample API used by Example Component whose method signatures are read from File. */ public class ExampleFileHello { public String sayHi() { return "Hello!"; } public String greetMe(String name) { return "Hello " + name; } public String greetUs(String name1, String name2) { return "Hello " + name1 + ", " + name2; } }
Generating the Javadoc metadata for ExampleJavadocHello
Because the metadata for ExampleJavadocHello
is provided as Javadoc, it is necessary to generate Javadoc for the sample Java API and install it into the camel-api-example-api
Maven artifact. The API POM file, camel-api-example-api/pom.xml
, configures the maven-javadoc-plugin
to perform this step automatically during the Maven build.
46.3. Generated Component Sub-Project
Overview
The Maven sub-project for building the new component is located under the camel-api-example/camel-api-example-component
project directory. In this section, we take a closer look at the generated example code and describe how it works.
Providing the Java API in the component POM
The Java API must be provided as a dependency in the component POM. For example, the sample Java API is defined as a dependency in the component POM file, camel-api-example-component/pom.xml
, as follows:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> ... <dependencies> ... <dependency> <groupId>org.jboss.fuse.example</groupId> <artifactId>camel-api-example-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> ... </dependencies> ... </project>
Providing the Javadoc metadata in the component POM
If you are using Javadoc metadata for all or part of the Java API, you must provide the Javadoc as a dependency in the component POM. There are two things to note about this dependency:
The Maven coordinates for the Javadoc are almost the same as for the Java API, except that you must also specify a
classifier
element, as follows:<classifier>javadoc</classifier>
You must declare the Javadoc to have
provided
scope, as follows:<scope>provided</scope>
For example, in the component POM, the Javadoc dependency is defined as follows:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> ... <dependencies> ... <!-- Component API javadoc in provided scope to read API signatures --> <dependency> <groupId>org.jboss.fuse.example</groupId> <artifactId>camel-api-example-api</artifactId> <version>1.0-SNAPSHOT</version> <classifier>javadoc</classifier> <scope>provided</scope> </dependency> ... </dependencies> ... </project>
Defining the file metadata for Example File Hello
The metadata for ExampleFileHello
is provided in a signature file. In general, this file must be created manually, but it has quite a simple format, which consists of a list of method signatures (one on each line). The example code provides the signature file, file-sig-api.txt
, in the directory, camel-api-example-component/signatures
, which has the following contents:
public String sayHi(); public String greetMe(String name); public String greetUs(String name1, String name2);
For more details about the signature file format, see the section called “Signature file metadata”.
Configuring the API mapping
One of the key features of the API component framework is that it automatically generates the code to perform API mapping. That is, generating stub code that maps endpoint URIs to method invocations on the Java API. The basic inputs to the API mapping are: the Java API, the Javadoc metadata, and/or the signature file metadata.
The component that performs the API mapping is the camel-api-component-maven-plugin
Maven plug-in, which is configured in the component POM. The following extract from the component POM shows how the camel-api-component-maven-plugin
plug-in is configured:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> ... <build> <defaultGoal>install</defaultGoal> <plugins> ... <!-- generate Component source and test source --> <plugin> <groupId>org.apache.camel</groupId> <artifactId>camel-api-component-maven-plugin</artifactId> <executions> <execution> <id>generate-test-component-classes</id> <goals> <goal>fromApis</goal> </goals> <configuration> <apis> <api> <apiName>hello-file</apiName> <proxyClass>org.jboss.fuse.example.api.ExampleFileHello</proxyClass> <fromSignatureFile>signatures/file-sig-api.txt</fromSignatureFile> </api> <api> <apiName>hello-javadoc</apiName> <proxyClass>org.jboss.fuse.example.api.ExampleJavadocHello</proxyClass> <fromJavadoc/> </api> </apis> </configuration> </execution> </executions> </plugin> ... </plugins> ... </build> ... </project>
The plug-in is configured by the configuration
element, which contains a single apis
child element to configure the classes of the Java API. Each API class is configured by an api
element, as follows:
apiName
The API name is a short name for the API class and is used as the
endpoint-prefix
part of an endpoint URI.NoteIf the API consists of just a single Java class, you can leave the
apiName
element empty, so that theendpoint-prefix
becomes redundant, and you can then specify the endpoint URI using the format shown in the section called “URI format for a single API class”.proxyClass
- The proxy class element specifies the fully-qualified name of the API class.
fromJavadoc
-
If the API class is accompanied by Javadoc metadata, you must indicate this by including the
fromJavadoc
element and the Javadoc itself must also be specified in the Maven file, as aprovided
dependency (see the section called “Providing the Javadoc metadata in the component POM”). fromSignatureFile
If the API class is accompanied by signature file metadata, you must indicate this by including the
fromSignatureFile
element, where the content of this element specifies the location of the signature file.NoteThe signature files do not get included in the final package built by Maven, because these files are needed only at build time, not at run time.
Generated component implementation
The API component consists of the following core classes (which must be implemented for every Camel component), under the camel-api-example-component/src/main/java
directory:
ExampleComponent
-
Represents the component itself. This class acts as a factory for endpoint instances (for example, instances of
ExampleEndpoint
). ExampleEndpoint
-
Represents an endpoint URI. This class acts as a factory for consumer endpoints (for example,
ExampleConsumer
) and as a factory for producer endpoints (for example,ExampleProducer
). ExampleConsumer
- Represents a concrete instance of a consumer endpoint, which is capable of consuming messages from the location specified in the endpoint URI.
ExampleProducer
- Represents a concrete instance of a producer endpoint, which is capable of sending messages to the location specified in the endpoint URI.
ExampleConfiguration
Can be used to define endpoint URI options. The URI options defined by this configuration class are not tied to any specific API class. That is, you can combine these URI options with any of the API classes or methods. This can be useful, for example, if you need to declare username and password credentials in order to connect to the remote service. The primary purpose of the
ExampleConfiguration
class is to provide values for parameters required to instantiate API classes, or classes that implement API interfaces. For example, these could be constructor parameters, or parameter values for a factory method or class.To implement a URI option,
option
, in this class, all that you need to do is implement the pair of accessor methods,getOption
andsetOption
. The component framework automatically parses the endpoint URI and injects the option values at run time.
ExampleComponent class
The generated ExampleComponent
class is defined as follows:
// Java package org.jboss.fuse.example; import org.apache.camel.CamelContext; import org.apache.camel.Endpoint; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.util.component.AbstractApiComponent; import org.jboss.fuse.example.internal.ExampleApiCollection; import org.jboss.fuse.example.internal.ExampleApiName; /** * Represents the component that manages {@link ExampleEndpoint}. */ @UriEndpoint(scheme = "example", consumerClass = ExampleConsumer.class, consumerPrefix = "consumer") public class ExampleComponent extends AbstractApiComponent<ExampleApiName, ExampleConfiguration, ExampleApiCollection> { public ExampleComponent() { super(ExampleEndpoint.class, ExampleApiName.class, ExampleApiCollection.getCollection()); } public ExampleComponent(CamelContext context) { super(context, ExampleEndpoint.class, ExampleApiName.class, ExampleApiCollection.getCollection()); } @Override protected ExampleApiName getApiName(String apiNameStr) throws IllegalArgumentException { return ExampleApiName.fromValue(apiNameStr); } @Override protected Endpoint createEndpoint(String uri, String methodName, ExampleApiName apiName, ExampleConfiguration endpointConfiguration) { return new ExampleEndpoint(uri, this, apiName, methodName, endpointConfiguration); } }
The important method in this class is createEndpoint
, which creates new endpoint instances. Typically, you do not need to change any of the default code in the component class. If there are any other objects with the same life cycle as this component, however, you might want to make those objects available from the component class (for example, by adding a methods to create those objects or by injecting those objects into the component).
ExampleEndpoint class
The generated ExampleEndpoint
class is defined as follows:
// Java package org.jboss.fuse.example; import java.util.Map; import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.util.component.AbstractApiEndpoint; import org.apache.camel.util.component.ApiMethod; import org.apache.camel.util.component.ApiMethodPropertiesHelper; import org.jboss.fuse.example.api.ExampleFileHello; import org.jboss.fuse.example.api.ExampleJavadocHello; import org.jboss.fuse.example.internal.ExampleApiCollection; import org.jboss.fuse.example.internal.ExampleApiName; import org.jboss.fuse.example.internal.ExampleConstants; import org.jboss.fuse.example.internal.ExamplePropertiesHelper; /** * Represents a Example endpoint. */ @UriEndpoint(scheme = "example", consumerClass = ExampleConsumer.class, consumerPrefix = "consumer") public class ExampleEndpoint extends AbstractApiEndpoint<ExampleApiName, ExampleConfiguration> { // TODO create and manage API proxy private Object apiProxy; public ExampleEndpoint(String uri, ExampleComponent component, ExampleApiName apiName, String methodName, ExampleConfiguration endpointConfiguration) { super(uri, component, apiName, methodName, ExampleApiCollection.getCollection().getHelper(apiName), endpointConfiguration); } public Producer createProducer() throws Exception { return new ExampleProducer(this); } public Consumer createConsumer(Processor processor) throws Exception { // make sure inBody is not set for consumers if (inBody != null) { throw new IllegalArgumentException("Option inBody is not supported for consumer endpoint"); } final ExampleConsumer consumer = new ExampleConsumer(this, processor); // also set consumer.* properties configureConsumer(consumer); return consumer; } @Override protected ApiMethodPropertiesHelper<ExampleConfiguration> getPropertiesHelper() { return ExamplePropertiesHelper.getHelper(); } protected String getThreadProfileName() { return ExampleConstants.THREAD_PROFILE_NAME; } @Override protected void afterConfigureProperties() { // TODO create API proxy, set connection properties, etc. switch (apiName) { case HELLO_FILE: apiProxy = new ExampleFileHello(); break; case HELLO_JAVADOC: apiProxy = new ExampleJavadocHello(); break; default: throw new IllegalArgumentException("Invalid API name " + apiName); } } @Override public Object getApiProxy(ApiMethod method, Map<String, Object> args) { return apiProxy; } }
In the context of the API component framework, one of the key steps performed by the endpoint class is to create an API proxy. The API proxy is an instance from the target Java API, whose methods are invoked by the endpoint. Because a Java API typically consists of many classes, it is necessary to pick the appropriate API class, based on the endpoint-prefix
appearing in the URI (recall that a URI has the general form, scheme://endpoint-prefix/endpoint
).
ExampleConsumer class
The generated ExampleConsumer
class is defined as follows:
// Java package org.jboss.fuse.example; import org.apache.camel.Processor; import org.apache.camel.util.component.AbstractApiConsumer; import org.jboss.fuse.example.internal.ExampleApiName; /** * The Example consumer. */ public class ExampleConsumer extends AbstractApiConsumer<ExampleApiName, ExampleConfiguration> { public ExampleConsumer(ExampleEndpoint endpoint, Processor processor) { super(endpoint, processor); } }
ExampleProducer class
The generated ExampleProducer
class is defined as follows:
// Java package org.jboss.fuse.example; import org.apache.camel.util.component.AbstractApiProducer; import org.jboss.fuse.example.internal.ExampleApiName; import org.jboss.fuse.example.internal.ExamplePropertiesHelper; /** * The Example producer. */ public class ExampleProducer extends AbstractApiProducer<ExampleApiName, ExampleConfiguration> { public ExampleProducer(ExampleEndpoint endpoint) { super(endpoint, ExamplePropertiesHelper.getHelper()); } }
ExampleConfiguration class
The generated ExampleConfiguration
class is defined as follows:
// Java package org.jboss.fuse.example; import org.apache.camel.spi.UriParams; /** * Component configuration for Example component. */ @UriParams public class ExampleConfiguration { // TODO add component configuration properties }
To add a URI option, option
, to this class, define a field of the appropriate type, and implement a corresponding pair of accessor methods, getOption
and setOption
. The component framework automatically parses the endpoint URI and injects the option values at run time.
This class is used to define general URI options, which can be combined with any API method. To define URI options tied to a specific API method, configure extra options in the API component Maven plug-in. See Section 47.7, “Extra Options” for details.
URI format
Recall the general format of an API component URI:
scheme://endpoint-prefix/endpoint?Option1=Value1&...&OptionN=ValueN
In general, a URI maps to a specific method invocation on the Java API. For example, suppose you want to invoke the API method, ExampleJavadocHello.greetMe("Jane Doe")
, the URI would be constructed, as follows:
- scheme
-
The API component scheme, as specified when you generated the code with the Maven archetype. In this case, the scheme is
example
. - endpoint-prefix
The API name, which maps to the API class defined by the
camel-api-component-maven-plugin
Maven plug-in configuration. For theExampleJavadocHello
class, the relevant configuration is:<configuration> <apis> <api> <apiName>hello-javadoc</apiName> <proxyClass>org.jboss.fuse.example.api.ExampleJavadocHello</proxyClass> <fromJavadoc/> </api> ... </apis> </configuration>
Which shows that the required
endpoint-prefix
ishello-javadoc
.- endpoint
-
The
endpoint
maps to the method name, which isgreetMe
. - Option1=Value1
-
The URI options specify method parameters. The
greetMe(String name)
method takes the single parameter,name
, which can be specified asname=Jane%20Doe
. If you want to define default values for options, you can do this by overriding theinterceptProperties
method (see Section 46.4, “Programming Model”).
Putting together the pieces of the URI, we see that we can invoke ExampleJavadocHello.greetMe("Jane Doe")
with the following URI:
example://hello-javadoc/greetMe?name=Jane%20Doe
Default component instance
In order to map the example
URI scheme to the default component instance, the Maven archetype creates the following file under the camel-api-example-component
sub-project:
src/main/resources/META-INF/services/org/apache/camel/component/example
This resource file is what enables the Camel core to identify the component associated with the example
URI scheme. Whenever you use an example://
URI in a route, Camel searches the classpath to look for the corresponding example
resource file. The example
file has the following contents:
class=org.jboss.fuse.example.ExampleComponent
This enables the Camel core to create a default instance of the ExampleComponent
component. The only time you would need to edit this file is if you refactor the name of the component class.
46.4. Programming Model
Overview
In the context of the API component framework, the main component implementation classes are derived from base classes in the org.apache.camel.util.component
package. These base classes define some methods which you can (optionally) override when you are implementing your component. In this section, we provide a brief description of those methods and how you might use them in your own component implementation.
Component methods to implement
In addition to the generated method implementations (which you usually do not need to modify), you can optionally override some of the following methods in the Component
class:
doStart()
-
(Optional) A callback to create resources for the component during a cold start. An alternative approach is to adopt the strategy of lazy initialization (creating resources only when they are needed). In fact, lazy initialization is often the best strategy, so the
doStart
method is often not needed. doStop()
(Optional) A callback to invoke code while the component is stopping. Stopping a component means that all of its resources are shut down, internal state is deleted, caches are cleared, and so on.
NoteCamel guarantees that
doStop
is always called when the currentCamelContext
shuts down, even if the correspondingdoStart
was never called.doShutdown
-
(Optional) A callback to invoke code while the
CamelContext
is shutting down. Whereas a stopped component can be restarted (with the semantics of a cold start), a component that gets shut down is completely finished. Hence, this callback represents the last chance to free up any resources belonging to the component.
What else to implement in the Component class?
The Component
class is the natural place to hold references to objects that have the same (or similar) life cycle to the component object itself. For example, if a component uses OAuth security, it would be natural to hold references to the required OAuth objects in the Component
class and to define methods in the Component
class for creating the OAuth objects.
Endpoint methods to implement
You can modify some of the generated methods and, optionally, override some inherited methods in the Endpoint
class, as follows:
afterConfigureProperties()
The main thing you need to do in this method is to create the appropriate type of proxy class (API class), to match the API name. The API name (which has already been extracted from the endpoint URI) is available either through the inherited
apiName
field or through thegetApiName
accessor. Typically, you would do a switch on theapiName
field to create the corresponding proxy class. For example:// Java private Object apiProxy; ... @Override protected void afterConfigureProperties() { // TODO create API proxy, set connection properties, etc. switch (apiName) { case HELLO_FILE: apiProxy = new ExampleFileHello(); break; case HELLO_JAVADOC: apiProxy = new ExampleJavadocHello(); break; default: throw new IllegalArgumentException("Invalid API name " + apiName); } }
getApiProxy(ApiMethod method, Map<String, Object> args)
Override this method to return the proxy instance that you created in
afterConfigureProperties
. For example:@Override public Object getApiProxy(ApiMethod method, Map<String, Object> args) { return apiProxy; }
In special cases, you might want to make the choice of proxy dependent on the API method and arguments. The
getApiProxy
gives you the flexibility to take this approach, if required.doStart()
-
(Optional) A callback to create resources during a cold start. Has the same semantics as
Component.doStart()
. doStop()
-
(Optional) A callback to invoke code while the component is stopping. Has the same semantics as
Component.doStop()
. doShutdown
-
(Optional) A callback to invoke code while the component is shutting down. Has the same semantics as
Component.doShutdown()
. interceptPropertyNames(Set<String> propertyNames)
(Optional) The API component framework uses the endpoint URI and supplied option values to determine which method to invoke (ambiguity could be due to overloading and aliases). If the component internally adds options or method parameters, however, the framework might need help in order to determine the right method to invoke. In this case, you must override the
interceptPropertyNames
method and add the extra (hidden or implicit) options to thepropertyNames
set. When the complete list of method parameters are provided in thepropertyNames
set, the framework will be able to identify the right method to invoke.NoteYou can override this method at the level of the
Endpoint
,Producer
orConsumer
class. The basic rule is, if an option affects both producer endpoints and consumer endpoints, override the method in theEndpoint
class.interceptProperties(Map<String,Object> properties)
(Optional) By overriding this method, you can modify or set the actual values of the options, before the API method is invoked. For example, you could use this method to set default values for some options, if necessary. In practice, it is often necessary to override both the
interceptPropertyNames
method and theinterceptProperty
method.NoteYou can override this method at the level of the
Endpoint
,Producer
orConsumer
class. The basic rule is, if an option affects both producer endpoints and consumer endpoints, override the method in theEndpoint
class.
Consumer methods to implement
You can optionally override some inherited methods in the Consumer
class, as follows:
interceptPropertyNames(Set<String> propertyNames)
-
(Optional) The semantics of this method are similar to
Endpoint.interceptPropertyNames
interceptProperties(Map<String,Object> properties)
-
(Optional) The semantics of this method are similar to
Endpoint.interceptProperties
doInvokeMethod(Map<String, Object> args)
(Optional) Overriding this method enables you to intercept the invocation of the Java API method. The most common reason for overriding this method is to customize the error handling around the method invocation. For example, a typical approach to overriding
doInvokeMethod
is shown in the following code fragment:// Java @Override protected Object doInvokeMethod(Map<String, Object> args) { try { return super.doInvokeMethod(args); } catch (RuntimeCamelException e) { // TODO - Insert custom error handling here! ... } }
You should invoke
doInvokeMethod
on the super-class, at some point in this implementation, to ensure that the Java API method gets invoked.interceptResult(Object methodResult, Exchange resultExchange)
-
(Optional) Do some additional processing on the result of the API method invocation. For example, you could add custom headers to the Camel exchange object,
resultExchange
, at this point. Object splitResult(Object result)
(Optional) By default, if the result of the method API invocation is a
java.util.Collection
object or a Java array, the API component framework splits the result into multiple exchange objects (so that a single invocation result is converted into multiple messages).If you want to change the default behaviour, you can override the
splitResult
method in the consumer endpoint. Theresult
argument contains the result of the API message invocation. If you want to split the result, you should return an array type.NoteYou can also switch off the default splitting behaviour by setting
consumer.splitResult=false
on the endpoint URI.
Producer methods to implement
You can optionally override some inherited methods in the Producer
class, as follows:
interceptPropertyNames(Set<String> propertyNames)
-
(Optional) The semantics of this method are similar to
Endpoint.interceptPropertyNames
interceptProperties(Map<String,Object> properties)
-
(Optional) The semantics of this method are similar to
Endpoint.interceptProperties
doInvokeMethod(Map<String, Object> args)
-
(Optional) The semantics of this method are similar to
Consumer.doInvokeMethod
. interceptResult(Object methodResult, Exchange resultExchange)
-
(Optional) The semantics of this method are similar to
Consumer.interceptResult
.
The Producer.splitResult()
method is never called, so it is not possible to split an API method result in the same way as you can for a consumer endpoint. To get a similar effect for a producer endpoint, you can use Camel’s split()
DSL command (one of the standard enterprise integration patterns) to split Collection
or array results.
Consumer polling and threading model
The default threading model for consumer endpoints in the API component framework is scheduled poll consumer. This implies that the API method in a consumer endpoint is invoked at regular, scheduled time intervals. For more details, see the section called “Scheduled poll consumer implementation”.
46.5. Sample Component Implementations
Overview
Several of the components distributed with Apache Camel have been implemented with the aid of the API component framework. If you want to learn more about the techniques for implementing Camel components using the framework, it is a good idea to study the source code of these component implementations.
Box.com
The Camel Box component shows how to model and invoke the third party Box.com Java SDK using the API component framework. It also demonstrates how the framework can be adapted to customize consumer polling, in order to support Box.com’s long polling API.
The Camel LinkedIn component demonstrates how to wrap a REST API provided in the form of WADL and XML schemas. The implementation of this component exploits the Apache CXF wadl2java
Maven plug-in to generate a Java API, which can then be wrapped using the API component framework.
This approach can be easily replicated to create a Camel component for any SaaS product or platform.
GoogleDrive
The Camel GoogleDrive component demonstrates how the API component framework can handle even Method Object style Google APIs. In this case, URI options are mapped to a method object, which is then invoked by overriding the doInvoke
method in the consumer and the producer.
Olingo2
The Camel Olingo2 component demonstrates how a callback-based Asynchronous API can be wrapped using the API component framework. This example shows how asynchronous processing can be pushed into underlying resources, like HTTP NIO connections, to make Camel endpoints more resource efficient.