You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2017/04/13 08:56:01 UTC
[2/2] camel git commit: Component docs
Component docs
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/81f7515e
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/81f7515e
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/81f7515e
Branch: refs/heads/master
Commit: 81f7515e545f3ffde83d61a0b52629951f67c233
Parents: 26f1e95
Author: Claus Ibsen <da...@apache.org>
Authored: Thu Apr 13 10:55:52 2017 +0200
Committer: Claus Ibsen <da...@apache.org>
Committed: Thu Apr 13 10:55:52 2017 +0200
----------------------------------------------------------------------
.../camel-scr/src/main/docs/camel-and-scr.adoc | 653 ------------------
components/camel-scr/src/main/docs/scr.adoc | 655 +++++++++++++++++++
2 files changed, 655 insertions(+), 653 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/81f7515e/components/camel-scr/src/main/docs/camel-and-scr.adoc
----------------------------------------------------------------------
diff --git a/components/camel-scr/src/main/docs/camel-and-scr.adoc b/components/camel-scr/src/main/docs/camel-and-scr.adoc
deleted file mode 100644
index b4cfe39..0000000
--- a/components/camel-scr/src/main/docs/camel-and-scr.adoc
+++ /dev/null
@@ -1,653 +0,0 @@
-## Working with Camel and SCR
-
-SCR stands for Service Component Runtime and is an implementation of
-OSGi Declarative Services specification. SCR enables any plain old Java
-object to expose and use OSGi services with no boilerplate code.
-
-OSGi framework knows your object by looking at SCR descriptor files in
-its bundle which are typically generated from Java annotations by a
-plugin such as `org.apache.felix:maven-scr-plugin`.
-
-Running Camel in an SCR bundle is a great alternative for Spring DM and
-Blueprint based solutions having significantly fewer lines of code
-between you and the OSGi framework. Using SCR your bundle can remain
-completely in Java world; there is no need to edit XML or properties
-files. This offers you full control over everything and means your IDE
-of choice knows exactly what is going on in your project.
-
-### Camel SCR support
-
-INFO: *Available as of Camel 2.15.0*.
-Camel-scr bundle is not included in Apache Camel versions prior 2.15.0,
-but the artifact itself can be used with any Camel version since 2.12.0.
-
-`org.apache.camel/camel-scr` bundle provides a base class,
-`AbstractCamelRunner`, which manages a Camel context for you and a
-helper class, `ScrHelper`, for using your SCR properties in unit tests.
-Camel-scr feature for Apache Karaf�defines all features and bundles
-required for running Camel in SCR bundles.
-
-`AbstractCamelRunner`�class ties CamelContext's lifecycle to Service
-Component's lifecycle and handles configuration with help of Camel's
-PropertiesComponent. All you have to do to make a Service Component out
-of your java class is to extend it from `AbstractCamelRunner`�and add
-the following `org.apache.felix.scr.annotations` on class level:
-
-*Add required annotations*
-
-[source,java]
----------------------------------------------------------------------------------------------------------------
-@Component
-@References({
- @Reference(name = "camelComponent",referenceInterface = ComponentResolver.class,
- cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, policy = ReferencePolicy.DYNAMIC,
- policyOption = ReferencePolicyOption.GREEDY, bind = "gotCamelComponent", unbind = "lostCamelComponent")
-})
----------------------------------------------------------------------------------------------------------------
-
-Then implement `getRouteBuilders()` method which returns the Camel
-routes you want to run:
-
-*Implement getRouteBuilders()*
-
-[source,java]
-------------------------------------------------------------------
- @Override
- protected List<RoutesBuilder> getRouteBuilders() {
- List<RoutesBuilder> routesBuilders = new ArrayList<>();
- routesBuilders.add(new YourRouteBuilderHere(registry));
- routesBuilders.add(new AnotherRouteBuilderHere(registry));
- return routesBuilders;
- }
-------------------------------------------------------------------
-
-And finally provide the default configuration with:
-
-*Default configuration in annotations*
-
-[source,java]
----------------------------------------------------------
-@Properties({
- @Property(name = "camelContextId", value = "my-test"),
- @Property(name = "active", value = "true"),
- @Property(name = "...", value = "..."),
- ...
-})
----------------------------------------------------------
-
-�
-
-That's all. And if you used `camel-archetype-scr` to generate a project
-all this is already taken care of.
-
-Below is an example of a complete Service Component class, generated by
-`camel-archetype-scr:`
-
-*CamelScrExample.java*
-
-[source,java]
--------------------------------------------------------------------------------------------------------------------------------------------
-// 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;
- }
-}
--------------------------------------------------------------------------------------------------------------------------------------------
-
-�
-
-`CamelContextId`�and `active`�properties control the CamelContext's name
-(defaults to "camel-runner-default") and whether it will be started or
-not (defaults to "false"), respectively. In addition to these you can
-add and use as many properties as you like. Camel's PropertiesComponent
-handles recursive properties and prefixing with fallback without
-problem.
-
-`AbstractCamelRunner`�will make these properties available to your
-RouteBuilders with help of Camel's PropertiesComponent and it will also
-inject these values into your Service Component's and RouteBuilder's
-fields when their names match. The fields can be declared with any
-visibility level, and many types are supported (String, int, boolean,
-URL, ...).
-
-Below is an example of a RouteBuilder class generated by
-`camel-archetype-scr`:
-
-�
-
-*CamelScrExampleRoute.java*
-
-[source,java]
------------------------------------------------------------------------------------------------
-// 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");
- }
-}
------------------------------------------------------------------------------------------------
-
-�
-
-Let's take a look at `CamelScrExampleRoute` in more detail.
-
-�
-
-[source,java]
-----------------------------------------
- // Configured fields
- private String camelRouteId;
- private Integer maximumRedeliveries;
- private Long redeliveryDelay;
- private Double backOffMultiplier;
- private Long maximumRedeliveryDelay;
-----------------------------------------
-
-The values of these fields are set with values from properties by
-matching their names.
-
-�
-
-[source,java]
------------------------------------------------
- // Add a bean to Camel context registry
- registry.put("test", "bean");
------------------------------------------------
-
-If you need to add some beans to CamelContext's registry for your
-routes, you can do it like this.
-
-�
-
-[source,java]
------------------------------------------------------------------------------------------------
- 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");
- }
------------------------------------------------------------------------------------------------
-
-It is a good idea to check that required parameters are set and they
-have meaningful values before allowing the routes to start.
-
-�
-
-[source,java]
-----------------------------------------------------------------
- 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();
-----------------------------------------------------------------
-
-Note that pretty much everything in the route is configured with
-properties. This essentially makes your RouteBuilder a template. SCR
-allows you to create more instances of your routes just by providing
-alternative configurations. More on this in section _Using Camel SCR
-bundle as a template_.
-
-### AbstractCamelRunner's lifecycle in SCR
-
-1. When component's configuration policy and mandatory references are
-satisfied SCR calls `activate()`. This creates and sets up a
-CamelContext through the following call chain:
-`activate()`�\u2192�`prepare()`�\u2192�`createCamelContext()`
-\u2192�`setupPropertiesComponent()` \u2192�`configure()` \u2192�`setupCamelContext()`.
-Finally, the context is scheduled to start after a delay defined in
-`AbstractCamelRunner.START_DELAY`�with `runWithDelay()`.
-2. When Camel components (`ComponentResolver` services, to be exact)
-are registered in OSGi, SCR calls `gotCamelComponent``()` which
-reschedules/delays the CamelContext start further by the same
-`AbstractCamelRunner.START_DELAY`. This in effect makes CamelContext
-wait until all Camel components are loaded or there is a sufficient gap
-between them. The same logic will tell a failed-to-start CamelContext to
-try again whenever we add more Camel components.
-3. When Camel components are unregistered SCR calls
-`lostCamelComponent``()`. This call does nothing.
-4. When one of the requirements that caused the call to `activate``()`
-is lost SCR will call `deactivate``()`. This will shutdown the
-CamelContext.
-
-In (non-OSGi) unit tests you should use `prepare()` \u2192�`run()` \u2192�`stop()`
-instead of `activate()` \u2192�`deactivate()` for more fine-grained control.
-Also, this allows us to avoid possible SCR specific operations in tests.
-
-### Using camel-archetype-scr
-
-The easiest way to create an Camel SCR bundle project is to use
-`camel-archetype-scr`�and Maven.
-
-You can generate a project with the following steps:
-
-*Generating a project*
-
-[source,text]
---------------------------------------------------------------------------------------------------------------
-$ mvn archetype:generate -Dfilter=org.apache.camel.archetypes:camel-archetype-scr
-�
-Choose archetype:
-1: 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: :
---------------------------------------------------------------------------------------------------------------
-
-Done!
-
-Now run:
-
-[source,java]
------------
-mvn install
------------
-
-and the bundle is ready to be deployed.
-
-### Unit testing Camel routes
-
-Service Component is a POJO and has no special requirements for
-(non-OSGi) unit testing. There are however some techniques that are
-specific to Camel SCR or just make testing easier.
-
-Below is an example unit test, generated by `camel-archetype-scr`:
-
-[source,java]
-------------------------------------------------------------------------------------------------------
-// This file was generated from org.apache.camel.archetypes/camel-archetype-scr/2.15-SNAPSHOT
-package example;
-
-import java.util.List;
-
-import org.apache.camel.scr.internal.ScrHelper;
-import org.apache.camel.builder.AdviceWithRouteBuilder;
-import org.apache.camel.component.mock.MockComponent;
-import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.model.ModelCamelContext;
-import org.apache.camel.model.RouteDefinition;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class CamelScrExampleTest {
-
- Logger log = LoggerFactory.getLogger(getClass());
-
- @Rule
- public TestName testName = new TestName();
-
- CamelScrExample integration;
- ModelCamelContext context;
-
- @Before
- public void setUp() throws Exception {
- log.info("*******************************************************************");
- log.info("Test: " + testName.getMethodName());
- log.info("*******************************************************************");
-
- // Set property prefix for unit testing
- System.setProperty(CamelScrExample.PROPERTY_PREFIX, "unit");
-
- // Prepare the integration
- integration = new CamelScrExample();
- integration.prepare(null, ScrHelper.getScrProperties(integration.getClass().getName()));
- context = integration.getContext();
-
- // Disable JMX for test
- context.disableJMX();
-
- // Fake a component for test
- context.addComponent("amq", new MockComponent());
- }
-
- @After
- public void tearDown() throws Exception {
- integration.stop();
- }
-
- @Test
- public void testRoutes() throws Exception {
- // Adjust routes
- List<RouteDefinition> routes = context.getRouteDefinitions();
-
- routes.get(0).adviceWith(context, new AdviceWithRouteBuilder() {
- @Override
- public void configure() throws Exception {
- // Replace "from" endpoint with direct:start
- replaceFromWith("direct:start");
- // Mock and skip result endpoint
- mockEndpoints("log:*");
- }
- });
-
- MockEndpoint resultEndpoint = context.getEndpoint("mock:log:foo", MockEndpoint.class);
- // resultEndpoint.expectedMessageCount(1); // If you want to just check the number of messages
- resultEndpoint.expectedBodiesReceived("hello"); // If you want to check the contents
-
- // Start the integration
- integration.run();
-
- // Send the test message
- context.createProducerTemplate().sendBody("direct:start", "hello");
-
- resultEndpoint.assertIsSatisfied();
- }
-}
-------------------------------------------------------------------------------------------------------
-
-�
-
-Now, let's take a look at the interesting bits one by one.
-
-*Using property prefixing*
-
-[source,java]
---------------------------------------------------------------------
- // Set property prefix for unit testing
- System.setProperty(CamelScrExample.PROPERTY_PREFIX, "unit");
---------------------------------------------------------------------
-
-This allows you to override parts of the configuration by prefixing
-properties with "unit.". For example, `unit.from` overrides `from` for
-the unit test.
-
-Prefixes can be used to handle the differences between the runtime
-environments where your routes might run. Moving the unchanged bundle
-through development, testing and production environments is a typical
-use case.
-
-�
-
-*Getting test configuration from annotations*
-
-[source,java]
-------------------------------------------------------------------------------------------------
- integration.prepare(null, ScrHelper.getScrProperties(integration.getClass().getName()));
-------------------------------------------------------------------------------------------------
-
-Here we configure the Service Component in test with the same properties
-that would be used in OSGi environment.
-
-�
-
-*Mocking components for test*
-
-[source,java]
----------------------------------------------------------
- // Fake a component for test
- context.addComponent("amq", new MockComponent());
----------------------------------------------------------
-
-Components that are not available in test can be mocked like this to
-allow the route to start.
-
-�
-
-*Adjusting routes for test*
-
-[source,java]
-------------------------------------------------------------------------
- // Adjust routes
- List<RouteDefinition> routes = context.getRouteDefinitions();
-
- routes.get(0).adviceWith(context, new AdviceWithRouteBuilder() {
- @Override
- public void configure() throws Exception {
- // Replace "from" endpoint with direct:start
- replaceFromWith("direct:start");
- // Mock and skip result endpoint
- mockEndpoints("log:*");
- }
- });
-------------------------------------------------------------------------
-
-Camel's AdviceWith feature allows routes to be modified for test.
-
-�
-
-*Starting the routes*
-
-[source,java]
---------------------------------
- // Start the integration
- integration.run();
---------------------------------
-
-Here we start the Service Component and along with it the routes.
-
-�
-
-*Sending a test message*
-
-[source,java]
----------------------------------------------------------------------------
- // Send the test message
- context.createProducerTemplate().sendBody("direct:start", "hello");
----------------------------------------------------------------------------
-
-Here we send a message to a route in test.
-
-### Running the bundle in Apache Karaf
-
-Once the bundle has been built with `mvn install` it's ready to be
-deployed.�To deploy the bundle on Apache Karaf perform the following
-steps on Karaf command line:
-
-*Deploying the bundle in Apache Karaf*
-
-[source,text]
-------------------------------------------------------------------------
-# 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 in the example route 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
-�
-# See how it's running
-karaf@root> log:tail -n 10
-�
-Press ctrl-c to stop watching the log.
-------------------------------------------------------------------------
-
-#### Overriding the default configuration
-
-By default, Service Component's configuration PID equals the fully
-qualified name of its class. You can change the example bundle's
-properties with Karaf's�`config:*` commands:
-
-*Override a property*
-
-[source,text]
-----------------------------------------------------------------------------------------
-# Override 'messageOk' property
-karaf@root> config:propset -p example.CamelScrExample messageOk "This is better logging"
-----------------------------------------------------------------------------------------
-
-Or you can change the configuration by editing property files in Karaf's
-`etc` folder.
-
-#### Using Camel SCR bundle as a template
-
-Let's say you have a Camel SCR bundle that implements an integration
-pattern that you use frequently, say, *from \u2192�to*, with success/failure
-logging and redelivery which also happens to be the pattern our example
-route implements. You probably don't want to create a separate bundle
-for every instance. No worries, SCR has you covered.
-
-Create a configuration PID for your Service Component, but add a tail
-with a dash and SCR will use that configuration to create a new instance
-of your component.
-
-*Creating a new Service Component instance*
-
-[source,text]
-------------------------------------------------------------------------
-# 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
-------------------------------------------------------------------------
-
-This will start a new CamelContext with your overridden properties. How
-convenient.
-
-### Notes
-
-When designing a Service Component to be a template you typically don't
-want it to start without a "tailed" configuration i.e. with the default
-configuration.
-
-To prevent your Service Component from starting with the default
-configuration add `policy = ConfigurationPolicy.REQUIRE `to the class
-level `@Component` annotation.
http://git-wip-us.apache.org/repos/asf/camel/blob/81f7515e/components/camel-scr/src/main/docs/scr.adoc
----------------------------------------------------------------------
diff --git a/components/camel-scr/src/main/docs/scr.adoc b/components/camel-scr/src/main/docs/scr.adoc
new file mode 100644
index 0000000..451af6a
--- /dev/null
+++ b/components/camel-scr/src/main/docs/scr.adoc
@@ -0,0 +1,655 @@
+## Working with Camel and SCR
+
+**deprecated**
+
+SCR stands for Service Component Runtime and is an implementation of
+OSGi Declarative Services specification. SCR enables any plain old Java
+object to expose and use OSGi services with no boilerplate code.
+
+OSGi framework knows your object by looking at SCR descriptor files in
+its bundle which are typically generated from Java annotations by a
+plugin such as `org.apache.felix:maven-scr-plugin`.
+
+Running Camel in an SCR bundle is a great alternative for Spring DM and
+Blueprint based solutions having significantly fewer lines of code
+between you and the OSGi framework. Using SCR your bundle can remain
+completely in Java world; there is no need to edit XML or properties
+files. This offers you full control over everything and means your IDE
+of choice knows exactly what is going on in your project.
+
+### Camel SCR support
+
+INFO: *Available as of Camel 2.15.0*.
+Camel-scr bundle is not included in Apache Camel versions prior 2.15.0,
+but the artifact itself can be used with any Camel version since 2.12.0.
+
+`org.apache.camel/camel-scr` bundle provides a base class,
+`AbstractCamelRunner`, which manages a Camel context for you and a
+helper class, `ScrHelper`, for using your SCR properties in unit tests.
+Camel-scr feature for Apache Karaf�defines all features and bundles
+required for running Camel in SCR bundles.
+
+`AbstractCamelRunner`�class ties CamelContext's lifecycle to Service
+Component's lifecycle and handles configuration with help of Camel's
+PropertiesComponent. All you have to do to make a Service Component out
+of your java class is to extend it from `AbstractCamelRunner`�and add
+the following `org.apache.felix.scr.annotations` on class level:
+
+*Add required annotations*
+
+[source,java]
+---------------------------------------------------------------------------------------------------------------
+@Component
+@References({
+ @Reference(name = "camelComponent",referenceInterface = ComponentResolver.class,
+ cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, policy = ReferencePolicy.DYNAMIC,
+ policyOption = ReferencePolicyOption.GREEDY, bind = "gotCamelComponent", unbind = "lostCamelComponent")
+})
+---------------------------------------------------------------------------------------------------------------
+
+Then implement `getRouteBuilders()` method which returns the Camel
+routes you want to run:
+
+*Implement getRouteBuilders()*
+
+[source,java]
+------------------------------------------------------------------
+ @Override
+ protected List<RoutesBuilder> getRouteBuilders() {
+ List<RoutesBuilder> routesBuilders = new ArrayList<>();
+ routesBuilders.add(new YourRouteBuilderHere(registry));
+ routesBuilders.add(new AnotherRouteBuilderHere(registry));
+ return routesBuilders;
+ }
+------------------------------------------------------------------
+
+And finally provide the default configuration with:
+
+*Default configuration in annotations*
+
+[source,java]
+---------------------------------------------------------
+@Properties({
+ @Property(name = "camelContextId", value = "my-test"),
+ @Property(name = "active", value = "true"),
+ @Property(name = "...", value = "..."),
+ ...
+})
+---------------------------------------------------------
+
+�
+
+That's all. And if you used `camel-archetype-scr` to generate a project
+all this is already taken care of.
+
+Below is an example of a complete Service Component class, generated by
+`camel-archetype-scr:`
+
+*CamelScrExample.java*
+
+[source,java]
+-------------------------------------------------------------------------------------------------------------------------------------------
+// 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;
+ }
+}
+-------------------------------------------------------------------------------------------------------------------------------------------
+
+�
+
+`CamelContextId`�and `active`�properties control the CamelContext's name
+(defaults to "camel-runner-default") and whether it will be started or
+not (defaults to "false"), respectively. In addition to these you can
+add and use as many properties as you like. Camel's PropertiesComponent
+handles recursive properties and prefixing with fallback without
+problem.
+
+`AbstractCamelRunner`�will make these properties available to your
+RouteBuilders with help of Camel's PropertiesComponent and it will also
+inject these values into your Service Component's and RouteBuilder's
+fields when their names match. The fields can be declared with any
+visibility level, and many types are supported (String, int, boolean,
+URL, ...).
+
+Below is an example of a RouteBuilder class generated by
+`camel-archetype-scr`:
+
+�
+
+*CamelScrExampleRoute.java*
+
+[source,java]
+-----------------------------------------------------------------------------------------------
+// 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");
+ }
+}
+-----------------------------------------------------------------------------------------------
+
+�
+
+Let's take a look at `CamelScrExampleRoute` in more detail.
+
+�
+
+[source,java]
+----------------------------------------
+ // Configured fields
+ private String camelRouteId;
+ private Integer maximumRedeliveries;
+ private Long redeliveryDelay;
+ private Double backOffMultiplier;
+ private Long maximumRedeliveryDelay;
+----------------------------------------
+
+The values of these fields are set with values from properties by
+matching their names.
+
+�
+
+[source,java]
+-----------------------------------------------
+ // Add a bean to Camel context registry
+ registry.put("test", "bean");
+-----------------------------------------------
+
+If you need to add some beans to CamelContext's registry for your
+routes, you can do it like this.
+
+�
+
+[source,java]
+-----------------------------------------------------------------------------------------------
+ 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");
+ }
+-----------------------------------------------------------------------------------------------
+
+It is a good idea to check that required parameters are set and they
+have meaningful values before allowing the routes to start.
+
+�
+
+[source,java]
+----------------------------------------------------------------
+ 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();
+----------------------------------------------------------------
+
+Note that pretty much everything in the route is configured with
+properties. This essentially makes your RouteBuilder a template. SCR
+allows you to create more instances of your routes just by providing
+alternative configurations. More on this in section _Using Camel SCR
+bundle as a template_.
+
+### AbstractCamelRunner's lifecycle in SCR
+
+1. When component's configuration policy and mandatory references are
+satisfied SCR calls `activate()`. This creates and sets up a
+CamelContext through the following call chain:
+`activate()`�\u2192�`prepare()`�\u2192�`createCamelContext()`
+\u2192�`setupPropertiesComponent()` \u2192�`configure()` \u2192�`setupCamelContext()`.
+Finally, the context is scheduled to start after a delay defined in
+`AbstractCamelRunner.START_DELAY`�with `runWithDelay()`.
+2. When Camel components (`ComponentResolver` services, to be exact)
+are registered in OSGi, SCR calls `gotCamelComponent``()` which
+reschedules/delays the CamelContext start further by the same
+`AbstractCamelRunner.START_DELAY`. This in effect makes CamelContext
+wait until all Camel components are loaded or there is a sufficient gap
+between them. The same logic will tell a failed-to-start CamelContext to
+try again whenever we add more Camel components.
+3. When Camel components are unregistered SCR calls
+`lostCamelComponent``()`. This call does nothing.
+4. When one of the requirements that caused the call to `activate``()`
+is lost SCR will call `deactivate``()`. This will shutdown the
+CamelContext.
+
+In (non-OSGi) unit tests you should use `prepare()` \u2192�`run()` \u2192�`stop()`
+instead of `activate()` \u2192�`deactivate()` for more fine-grained control.
+Also, this allows us to avoid possible SCR specific operations in tests.
+
+### Using camel-archetype-scr
+
+The easiest way to create an Camel SCR bundle project is to use
+`camel-archetype-scr`�and Maven.
+
+You can generate a project with the following steps:
+
+*Generating a project*
+
+[source,text]
+--------------------------------------------------------------------------------------------------------------
+$ mvn archetype:generate -Dfilter=org.apache.camel.archetypes:camel-archetype-scr
+�
+Choose archetype:
+1: 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: :
+--------------------------------------------------------------------------------------------------------------
+
+Done!
+
+Now run:
+
+[source,java]
+-----------
+mvn install
+-----------
+
+and the bundle is ready to be deployed.
+
+### Unit testing Camel routes
+
+Service Component is a POJO and has no special requirements for
+(non-OSGi) unit testing. There are however some techniques that are
+specific to Camel SCR or just make testing easier.
+
+Below is an example unit test, generated by `camel-archetype-scr`:
+
+[source,java]
+------------------------------------------------------------------------------------------------------
+// This file was generated from org.apache.camel.archetypes/camel-archetype-scr/2.15-SNAPSHOT
+package example;
+
+import java.util.List;
+
+import org.apache.camel.scr.internal.ScrHelper;
+import org.apache.camel.builder.AdviceWithRouteBuilder;
+import org.apache.camel.component.mock.MockComponent;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.model.ModelCamelContext;
+import org.apache.camel.model.RouteDefinition;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class CamelScrExampleTest {
+
+ Logger log = LoggerFactory.getLogger(getClass());
+
+ @Rule
+ public TestName testName = new TestName();
+
+ CamelScrExample integration;
+ ModelCamelContext context;
+
+ @Before
+ public void setUp() throws Exception {
+ log.info("*******************************************************************");
+ log.info("Test: " + testName.getMethodName());
+ log.info("*******************************************************************");
+
+ // Set property prefix for unit testing
+ System.setProperty(CamelScrExample.PROPERTY_PREFIX, "unit");
+
+ // Prepare the integration
+ integration = new CamelScrExample();
+ integration.prepare(null, ScrHelper.getScrProperties(integration.getClass().getName()));
+ context = integration.getContext();
+
+ // Disable JMX for test
+ context.disableJMX();
+
+ // Fake a component for test
+ context.addComponent("amq", new MockComponent());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ integration.stop();
+ }
+
+ @Test
+ public void testRoutes() throws Exception {
+ // Adjust routes
+ List<RouteDefinition> routes = context.getRouteDefinitions();
+
+ routes.get(0).adviceWith(context, new AdviceWithRouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ // Replace "from" endpoint with direct:start
+ replaceFromWith("direct:start");
+ // Mock and skip result endpoint
+ mockEndpoints("log:*");
+ }
+ });
+
+ MockEndpoint resultEndpoint = context.getEndpoint("mock:log:foo", MockEndpoint.class);
+ // resultEndpoint.expectedMessageCount(1); // If you want to just check the number of messages
+ resultEndpoint.expectedBodiesReceived("hello"); // If you want to check the contents
+
+ // Start the integration
+ integration.run();
+
+ // Send the test message
+ context.createProducerTemplate().sendBody("direct:start", "hello");
+
+ resultEndpoint.assertIsSatisfied();
+ }
+}
+------------------------------------------------------------------------------------------------------
+
+�
+
+Now, let's take a look at the interesting bits one by one.
+
+*Using property prefixing*
+
+[source,java]
+--------------------------------------------------------------------
+ // Set property prefix for unit testing
+ System.setProperty(CamelScrExample.PROPERTY_PREFIX, "unit");
+--------------------------------------------------------------------
+
+This allows you to override parts of the configuration by prefixing
+properties with "unit.". For example, `unit.from` overrides `from` for
+the unit test.
+
+Prefixes can be used to handle the differences between the runtime
+environments where your routes might run. Moving the unchanged bundle
+through development, testing and production environments is a typical
+use case.
+
+�
+
+*Getting test configuration from annotations*
+
+[source,java]
+------------------------------------------------------------------------------------------------
+ integration.prepare(null, ScrHelper.getScrProperties(integration.getClass().getName()));
+------------------------------------------------------------------------------------------------
+
+Here we configure the Service Component in test with the same properties
+that would be used in OSGi environment.
+
+�
+
+*Mocking components for test*
+
+[source,java]
+---------------------------------------------------------
+ // Fake a component for test
+ context.addComponent("amq", new MockComponent());
+---------------------------------------------------------
+
+Components that are not available in test can be mocked like this to
+allow the route to start.
+
+�
+
+*Adjusting routes for test*
+
+[source,java]
+------------------------------------------------------------------------
+ // Adjust routes
+ List<RouteDefinition> routes = context.getRouteDefinitions();
+
+ routes.get(0).adviceWith(context, new AdviceWithRouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ // Replace "from" endpoint with direct:start
+ replaceFromWith("direct:start");
+ // Mock and skip result endpoint
+ mockEndpoints("log:*");
+ }
+ });
+------------------------------------------------------------------------
+
+Camel's AdviceWith feature allows routes to be modified for test.
+
+�
+
+*Starting the routes*
+
+[source,java]
+--------------------------------
+ // Start the integration
+ integration.run();
+--------------------------------
+
+Here we start the Service Component and along with it the routes.
+
+�
+
+*Sending a test message*
+
+[source,java]
+---------------------------------------------------------------------------
+ // Send the test message
+ context.createProducerTemplate().sendBody("direct:start", "hello");
+---------------------------------------------------------------------------
+
+Here we send a message to a route in test.
+
+### Running the bundle in Apache Karaf
+
+Once the bundle has been built with `mvn install` it's ready to be
+deployed.�To deploy the bundle on Apache Karaf perform the following
+steps on Karaf command line:
+
+*Deploying the bundle in Apache Karaf*
+
+[source,text]
+------------------------------------------------------------------------
+# 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 in the example route 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
+�
+# See how it's running
+karaf@root> log:tail -n 10
+�
+Press ctrl-c to stop watching the log.
+------------------------------------------------------------------------
+
+#### Overriding the default configuration
+
+By default, Service Component's configuration PID equals the fully
+qualified name of its class. You can change the example bundle's
+properties with Karaf's�`config:*` commands:
+
+*Override a property*
+
+[source,text]
+----------------------------------------------------------------------------------------
+# Override 'messageOk' property
+karaf@root> config:propset -p example.CamelScrExample messageOk "This is better logging"
+----------------------------------------------------------------------------------------
+
+Or you can change the configuration by editing property files in Karaf's
+`etc` folder.
+
+#### Using Camel SCR bundle as a template
+
+Let's say you have a Camel SCR bundle that implements an integration
+pattern that you use frequently, say, *from \u2192�to*, with success/failure
+logging and redelivery which also happens to be the pattern our example
+route implements. You probably don't want to create a separate bundle
+for every instance. No worries, SCR has you covered.
+
+Create a configuration PID for your Service Component, but add a tail
+with a dash and SCR will use that configuration to create a new instance
+of your component.
+
+*Creating a new Service Component instance*
+
+[source,text]
+------------------------------------------------------------------------
+# 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
+------------------------------------------------------------------------
+
+This will start a new CamelContext with your overridden properties. How
+convenient.
+
+### Notes
+
+When designing a Service Component to be a template you typically don't
+want it to start without a "tailed" configuration i.e. with the default
+configuration.
+
+To prevent your Service Component from starting with the default
+configuration add `policy = ConfigurationPolicy.REQUIRE `to the class
+level `@Component` annotation.