Chapter 45. Introduction to the API Component Framework
The API component framework helps you with the challenge of implementing complex Camel components based on a large Java API.
45.1. What is the API Component Framework?
For components with a small number of options, the standard approach to implementing components (Chapter 38, Implementing a Component) is quite effective. Where it starts to become problematic, however, is when you need to implement a component with a large number of options. This problem becomes dramatic when it comes to enterprise-level components, which can require you to wrap an API consisting of hundreds of operations. Such components require a large effort to create and maintain.
The API component framework was developed precisely to deal with the challenge of implementing such components.
Turning APIs into components
Experience of implementing Camel components based on Java APIs has shown that a lot of the work is routine and mechanical. It consists of taking a particular Java method, mapping it to a particular URI syntax, and enabling the user to set the method parameters through URI options. This type of work is an obvious candidate for automation and code generation.
Generic URI format
The first step in automating the implementation of a Java API is to design a standard way of mapping an API method to a URI. For this we need to define a generic URI format, which can be used to wrap any Java API. Hence, the API component framework defines the following syntax for endpoint URIs:
scheme is the default URI scheme defined by the component;
endpoint-prefix is a short API name, which maps to one of the classes or interfaces from the wrapped Java API;
endpoint maps to a method name; and the URI options map to method argument names.
URI format for a single API class
In the case where an API consists of just a single Java class, the
endpoint-prefix part of the URI becomes redundant, and you can specify the URI in the following, shorter format:
To enable this URI format, it is also necessary for the component implementor to leave the
apiName element blank in the configuration of the API component Maven plug-in. For more information, see the the section called “Configuring the API mapping” section.
Reflection and metadata
In order to map Java method invocations to a URI syntax, it is obvious that some form of reflection mechanism is needed. But the standard Java reflection API suffers from a notable limitation: it does not preserve method argument names. This is a problem, because we need the method argument names in order to generate meaningful URI option names. The solution is to provide metadata in alternative format: either as Javadoc or in method signature files.
Javadoc is an ideal form of metadata for the API component framework, because it preserves the complete method signature, including method argument names. It is also easy to generate (particularly, using
maven-javadoc-plugin) and, in many cases, is already provided in a third-party library.
Method signature files
If Javadoc is unavailable or unsuitable for some reason, the API component framework also supports an alternative source of metadata: the method signature files. A signature file is a simple text file which consists of a list of Java method signatures. It is relatively easy to create these files manually by copying and pasting from Java code (and lightly editing the resulting files).
What does the framework consist of?
From the perspective of a component developer, the API component framework consists of a number of different elements, as follows:
- A Maven archetype
camel-archetype-api-componentMaven archetype is used to generate skeleton code for the component implementation.
- A Maven plug-in
camel-api-component-maven-pluginMaven plug-in is responsible for generating the code that implements the mapping between the Java API and the endpoint URI syntax.
- Specialized base classes
To support the programming model of the API component framework, the Apache Camel core provides a specialized API in the
org.apache.camel.util.componentpackage. Amongst other things, this API provides specialized base classes for the component, endpoint, consumer, and producer classes.
45.2. How to use the Framework
The procedure for implementing a component using the API framework involve a mixture of automated code generation, implementing Java code, and customizing the build, by editing Maven POM files. The following figure gives an overview of this development process.
Figure 45.1. Using the API Component Framework
The starting point for your API component is always a Java API. Generally speaking, in the context of Camel, this usually means a Java client API, which connects to a remote server endpoint. The first question is, where does the Java API come from? Here are a few possibilities:
- Implement the Java API yourself (though this typically would involve a lot of work and is generally not the preferred approach).
- Use a third-party Java API. For example, the Apache Camel Box component is based on the third-party Box Java SDK library.
Generate the Java API from a language-neutral interface. For example, the Apache Camel LinkedIn component obtains its Java API by converting a WADL description of its REST services to Java (using the Apache CXF
You have the option of providing metadata for the Java API in the form of Javadoc (which is needed for generating code in the API component framework). If you use a third-party Java API from a Maven repository, you will usually find that the Javadoc is already provided in the Maven artifact. But even in the cases where Javadoc is not provided, you can easily generate it, using the
maven-javadoc-plugin Maven plug-in.
Currently, there is a limitation in the processing of Javadoc metadata, such that generic nesting is not supported. For example,
java.util.List<String> is supported, but
java.util.List<java.util.List<String>> is not. The workaround is to specify the nested generic type as
java.util.List<java.util.List> in a signature file.
Signature file metadata
If for some reason it is not convenient to provide Java API metadata in the form of Javadoc, you have the option of providing metadata in the form of signature files. The signature files consist of a list of method signatures (one method signature per line). These files can be created manually and are needed only at build time.
Note the following points about signature files:
- You must create one signature file for each proxy class (Java API class).
The method signatures should not throw an exception. All exceptions raised at runtime are wrapped in a
RuntimeCamelExceptionand returned from the endpoint.
Class names that specify the type of an argument must be fully-qualified class names (except for the
java.lang.\*types). There is no mechanism for importing package names.
Currently, there is a limitation in the signature parser, such that generic nesting is not supported. For example,
java.util.List<String>is supported, whereas
java.util.List<java.util.List<String>>is not. The workaround is to specify the nested generic type as
The following shows a simple example of the contents of a signature file:
public String sayHi(); public String greetMe(String name); public String greetUs(String name1, String name2);
Generate starting code with the Maven archetype
The easiest way to get started developing an API component is to generate an initial Maven project using the
camel-archetype-api-component Maven archetype. For details of how to run the archetype, see Section 46.1, “Generate Code with the Maven Archetype”.
After you run the Maven archetype, you will find two sub-projects under the generated
- This project contains the Java API, which forms the basis of the API component. When you build this project, it packages up the Java API in a Maven bundle and generates the requisite Javadoc as well. If the Java API and Javadoc are already provided by a third-party, however, you do not need this sub-project.
- This project contains the skeleton code for the API component.
Edit component classes
You can edit the skeleton code in
ProjectName-component to develop your own component implementation. The following generated classes make up the core of the skeleton implementation:
ComponentNameComponent ComponentNameEndpoint ComponentNameConsumer ComponentNameProducer ComponentNameConfiguration
Customize POM files
You also need to edit the Maven POM files to customize the build, and to configure the
camel-api-component-maven-plugin Maven plug-in.
Configure the camel-api-component-maven-plugin
The most important aspect of configuring the POM files is the configuration of the
camel-api-component-maven-plugin Maven plug-in. This plug-in is responsible for generating the mapping between API methods and endpoint URIs, and by editing the plug-in configuration, you can customize the mapping.
For example, in the
ProjectName-component/pom.xml file, the following
camel-api-component-maven-plugin plug-in configuration shows a minimal configuration for an API class called
<configuration> <apis> <api> <apiName>hello-javadoc</apiName> <proxyClass>org.jboss.fuse.example.api.ExampleJavadocHello</proxyClass> <fromJavadoc/> </api> </apis> </configuration>
In this example, the
hello-javadoc API name is mapped to the
ExampleJavadocHello class, which means you can invoke methods from this class using URIs of the form,
scheme://hello-javadoc/endpoint. The presence of the
fromJavadoc element indicates that the
ExampleJavadocHello class gets its metadata from Javadoc.
OSGi bundle configuration
The sample POM for the component sub-project,
ProjectName-component/pom.xml, is configured to package the component as an OSGi bundle. The component POM includes a sample configuration of the
maven-bundle-plugin. You should customize the configuration of the
maven-bundle-plugin plug-in, to ensure that Maven generates a properly configured OSGi bundle for your component.
Build the component
When you build the component with Maven (for example, by using
mvn clean package), the
camel-api-component-maven-plugin plug-in automatically generates the API mapping classes (which define the mapping between the Java API and the endpoint URI syntax), placing them into the
target/classes project subdirectory. When you are dealing with a large and complex Java API, this generated code actually constitutes the bulk of the component source code.
When the Maven build completes, the compiled code and resources are packaged up as an OSGi bundle and stored in your local Maven repository as a Maven artifact.