55.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.
Note
Camel guarantees that doStop is always called when the current CamelContext shuts down, even if the corresponding doStart 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 the getApiName accessor. Typically, you would do a switch on the apiName 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 the propertyNames set. When the complete list of method parameters are provided in the propertyNames set, the framework will be able to identify the right method to invoke.
Note
You can override this method at the level of the Endpoint, Producer or Consumer class. The basic rule is, if an option affects both producer endpoints and consumer endpoints, override the method in the Endpoint 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 the interceptProperty method.
Note
You can override this method at the level of the Endpoint, Producer or Consumer class. The basic rule is, if an option affects both producer endpoints and consumer endpoints, override the method in the Endpoint 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. The result argument contains the result of the API message invocation. If you want to split the result, you should return an array type.
Note
You 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.
Note
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”.