Chapter 12. Service Component Runtime
Abstract
Service Component Runtime (SCR) is an implementation of OSGi Declarative Services specification. It enables any plain old Java object to expose and use OSGi services with no boilerplate code.
Working with Camel and SCR
Apache Camel SCR component provides an integration of Camel with the OSGi Service Component Runtime.
OSGi framework has ability to know the object by looking at SCR descriptor file in its bundle which are generated from Java annotations by a plugin such as org.apache.felix:maven-scr-plugin
. Using SCR, the bundle remains completely in Java world. There is no need to edit XML
or properties file. It offers you full control over the project.
Creating a Service Component
Following are the steps to create a service component out of your java class.
Add the required
org.apache.felix.scr.annotations
at class level. For example,@Component @References({ @Reference(name = "camelComponent",referenceInterface = ComponentResolver.class, cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, bind = "gotCamelComponent", unbind = "lostCamelComponent") })
Implement the
getRouteBuilders()
method that returns the Camel route you want to run. For example,@Override protected List<RoutesBuilder> getRouteBuilders() { List<RoutesBuilder> routesBuilders = new ArrayList<>(); routesBuilders.add(new YourRouteBuilderHere(registry)); routesBuilders.add(new AnotherRouteBuilderHere(registry)); return routesBuilders; }
Finally, enter the default configuration in annotations.
@Properties({ @Property(name = "camelContextId", value = "my-test"), @Property(name = "active", value = "true"), @Property(name = "...", value = "..."), ... })
Example of a Service Component class
The following example illustrates the use of camel-archetype-scr
to generate a complete service component class:
// This file was generated from org.apache.camel.archetypes/camel-archetype-scr/2.15-SNAPSHOT package example; import java.util.ArrayList; import java.util.List; import org.apache.camel.scr.AbstractCamelRunner; import example.internal.CamelScrExampleRoute; import org.apache.camel.RoutesBuilder; import org.apache.camel.spi.ComponentResolver; import org.apache.felix.scr.annotations.*; @Component(label = CamelScrExample.COMPONENT_LABEL, description = CamelScrExample.COMPONENT_DESCRIPTION, immediate = true, metatype = true) @Properties({ @Property(name = "camelContextId", value = "camel-scr-example"), @Property(name = "camelRouteId", value = "foo/timer-log"), @Property(name = "active", value = "true"), @Property(name = "from", value = "timer:foo?period=5000"), @Property(name = "to", value = "log:foo?showHeaders=true"), @Property(name = "messageOk", value = "Success: {{from}} -> {{to}}"), @Property(name = "messageError", value = "Failure: {{from}} -> {{to}}"), @Property(name = "maximumRedeliveries", value = "0"), @Property(name = "redeliveryDelay", value = "5000"), @Property(name = "backOffMultiplier", value = "2"), @Property(name = "maximumRedeliveryDelay", value = "60000") }) @References({ @Reference(name = "camelComponent",referenceInterface = ComponentResolver.class, cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, bind = "gotCamelComponent", unbind = "lostCamelComponent") }) public class CamelScrExample extends AbstractCamelRunner { public static final String COMPONENT_LABEL = "example.CamelScrExample"; public static final String COMPONENT_DESCRIPTION = "This is the description for camel-scr-example."; @Override protected List<RoutesBuilder> getRouteBuilders() { List<RoutesBuilder> routesBuilders = new ArrayList<>(); routesBuilders.add(new CamelScrExampleRoute(registry)); return routesBuilders; } }
Example of a RouteBuilder class
The following example illustrates the use of camel-archetype-scr
to generate a RouteBuilder
class:
// This file was generated from org.apache.camel.archetypes/camel-archetype-scr/2.15-SNAPSHOT package example.internal; import org.apache.camel.LoggingLevel; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.SimpleRegistry; import org.apache.commons.lang.Validate; public class CamelScrExampleRoute extends RouteBuilder { SimpleRegistry registry; // Configured fields private String camelRouteId; private Integer maximumRedeliveries; private Long redeliveryDelay; private Double backOffMultiplier; private Long maximumRedeliveryDelay; public CamelScrExampleRoute(final SimpleRegistry registry) { this.registry = registry; } @Override public void configure() throws Exception { checkProperties(); // Add a bean to Camel context registry registry.put("test", "bean"); errorHandler(defaultErrorHandler() .retryAttemptedLogLevel(LoggingLevel.WARN) .maximumRedeliveries(maximumRedeliveries) .redeliveryDelay(redeliveryDelay) .backOffMultiplier(backOffMultiplier) .maximumRedeliveryDelay(maximumRedeliveryDelay)); from("{{from}}") .startupOrder(2) .routeId(camelRouteId) .onCompletion() .to("direct:processCompletion") .end() .removeHeaders("CamelHttp*") .to("{{to}}"); from("direct:processCompletion") .startupOrder(1) .routeId(camelRouteId + ".completion") .choice() .when(simple("${exception} == null")) .log("{{messageOk}}") .otherwise() .log(LoggingLevel.ERROR, "{{messageError}}") .end(); } } public void checkProperties() { Validate.notNull(camelRouteId, "camelRouteId property is not set"); Validate.notNull(maximumRedeliveries, "maximumRedeliveries property is not set"); Validate.notNull(redeliveryDelay, "redeliveryDelay property is not set"); Validate.notNull(backOffMultiplier, "backOffMultiplier property is not set"); Validate.notNull(maximumRedeliveryDelay, "maximumRedeliveryDelay property is not set"); } }
Using Apache Camel SCR bundle as a template
If you have a Camel SCR bundle that implements an integration pattern that you use frequently, then, probably there is no need to create a separate bundle for every instance.
The following example illustrates how to use a Camel SCR bundle as a template. It includes the following steps:
- Create a configuration PID for your service component and add a tail with a dash.
- Camel SCR will use the configuration to create a new instance of your component.
Finally, you can start a new
CamelContext
with your overridden properties.# Create a PID with a tail karaf@root> config:edit example.CamelScrExample-anotherone # Override some properties karaf@root> config:propset camelContextId my-other-context karaf@root> config:propset to "file://removeme?fileName=removemetoo.txt" # Save the PID karaf@root> config:update
NoteMake sure that your service component does not start with the default configuration. To prevent this, add
policy = ConfigurationPolicy.REQUIRE
to the class level at component annotation.
Using Apache camel-archetype-scr
With the help of Apache camel-archetype-scr
and maven, you can easily create Apache Camel SCR bundle project. It includes the following steps:
Run the following command:
$ mvn archetype:generate -Dfilter=org.apache.camel.archetypes:camel-archetype-scr Choose archetype: local -> org.apache.camel.archetypes:camel-archetype-scr (Creates a new Camel SCR bundle project for Karaf) Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): : 1 Define value for property 'groupId': : example [INFO] Using property: groupId = example Define value for property 'artifactId': : camel-scr-example Define value for property 'version': 1.0-SNAPSHOT: : Define value for property 'package': example: : [INFO] Using property: archetypeArtifactId = camel-archetype-scr [INFO] Using property: archetypeGroupId = org.apache.camel.archetypes [INFO] Using property: archetypeVersion = 2.15-SNAPSHOT Define value for property 'className': : CamelScrExample Confirm properties configuration: groupId: example artifactId: camel-scr-example version: 1.0-SNAPSHOT package: example archetypeArtifactId: camel-archetype-scr archetypeGroupId: org.apache.camel.archetypes archetypeVersion: 2.15-SNAPSHOT className: CamelScrExample Y: :
Run Apache Maven.
NoteFor details on setting up Apache Maven to work with Red Hat JBoss Fuse, see Building with Maven in Red Hat JBoss Fuse Deploying into Apache Karaf on the Red Hat Customer Portal
You can now deploy the bundle. To deploy the bundle on Apache Karaf, perform the following steps on Karaf command line:
# Add Camel feature repository karaf@root> features:chooseurl camel 2.15-SNAPSHOT # Install camel-scr feature karaf@root> features:install camel-scr # Install commons-lang, used to validate parameters karaf@root> osgi:install mvn:commons-lang/commons-lang/2.6 # Install and start your bundle karaf@root> osgi:install -s mvn:example/camel-scr-example/1.0-SNAPSHOT # View the log. karaf@root> log:tail -n 10 Press ctrl-c to stop the log.
By default, the Service Component’s configuration PID equals the fully qualified name of its class. You can change the properties of a bundle with Apache Karaf’s
config.*
commands:# Override the messageOk property karaf@root> config:propset -p example.CamelScrExample messageOk "This is better logging".
You can also change the configuration by editing the property file in Apache Karaf’s
etc
directory.