Repository: camel
Updated Branches:
  refs/heads/master a9e987fe2 -> d3a69dc81


Initial commit for camel-scr


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/d742358e
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/d742358e
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/d742358e

Branch: refs/heads/master
Commit: d742358e4080fd3dfd9bc4414495e3c5b2420542
Parents: a9e987f
Author: Jyrki Ruuskanen <yur...@kotikone.fi>
Authored: Wed Nov 5 21:49:17 2014 +0200
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Sun Nov 9 09:31:29 2014 +0100

----------------------------------------------------------------------
 components/camel-scr/pom.xml                    |  80 ++++++
 .../apache/camel/scr/AbstractCamelRunner.java   | 263 +++++++++++++++++++
 .../java/org/apache/camel/scr/ScrHelper.java    |  80 ++++++
 .../camel/scr/AbstractCamelRunnerTest.java      | 105 ++++++++
 .../apache/camel/scr/ConcreteCamelRunner.java   |  98 +++++++
 .../org/apache/camel/scr/TestRouteBuilder.java  |  43 +++
 .../org/apache/camel/scr/TestRouteBuilder2.java |  13 +
 .../src/test/resources/log4j.properties         |  18 ++
 components/pom.xml                              |   1 +
 parent/pom.xml                                  |   1 +
 tooling/archetypes/camel-archetype-scr/pom.xml  |  79 ++++++
 .../META-INF/maven/archetype-metadata.xml       |  47 ++++
 .../main/resources/archetype-resources/pom.xml  | 219 +++++++++++++++
 .../src/main/java/__className__.java            |  47 ++++
 .../main/java/internal/__className__Route.java  |  79 ++++++
 .../src/main/resources/default.properties       |   1 +
 .../src/main/resources/log4j.properties         |  17 ++
 .../src/test/java/__className__Test.java        | 103 ++++++++
 .../src/test/resources/log4j.properties         |  12 +
 .../camel-scr-example/archetype.properties      |   9 +
 .../projects/camel-scr-example/goal.txt         |   1 +
 tooling/archetypes/pom.xml                      |   1 +
 22 files changed, 1317 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/components/camel-scr/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-scr/pom.xml b/components/camel-scr/pom.xml
new file mode 100644
index 0000000..0e495dc
--- /dev/null
+++ b/components/camel-scr/pom.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<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/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>components</artifactId>
+        <groupId>org.apache.camel</groupId>
+        <version>2.15-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-scr</artifactId>
+    <name>Camel :: SCR</name>
+    <description>Camel SCR support</description>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core-osgi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+            <version>${felix-framework-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <version>${felix-scr-annotations-version}</version>
+        </dependency>
+
+        <!-- logging -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+            <version>${commons-lang-version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/components/camel-scr/src/main/java/org/apache/camel/scr/AbstractCamelRunner.java
----------------------------------------------------------------------
diff --git 
a/components/camel-scr/src/main/java/org/apache/camel/scr/AbstractCamelRunner.java
 
b/components/camel-scr/src/main/java/org/apache/camel/scr/AbstractCamelRunner.java
new file mode 100644
index 0000000..436c99d
--- /dev/null
+++ 
b/components/camel-scr/src/main/java/org/apache/camel/scr/AbstractCamelRunner.java
@@ -0,0 +1,263 @@
+package org.apache.camel.scr;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.component.properties.PropertiesComponent;
+import org.apache.camel.core.osgi.OsgiDefaultCamelContext;
+import org.apache.camel.core.osgi.utils.BundleDelegatingClassLoader;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.ExplicitCamelContextNameStrategy;
+import org.apache.camel.impl.SimpleRegistry;
+import org.apache.camel.model.ModelCamelContext;
+import org.apache.camel.spi.ComponentResolver;
+import org.apache.camel.util.ReflectionHelper;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.net.URI;
+import java.net.URL;
+import java.util.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+public abstract class AbstractCamelRunner implements Runnable {
+
+    protected Logger log = LoggerFactory.getLogger(getClass());
+    protected ModelCamelContext context;
+    protected SimpleRegistry registry = new SimpleRegistry();
+
+    private ScheduledExecutorService executor = 
Executors.newSingleThreadScheduledExecutor();
+    private ScheduledFuture starter;
+    private boolean activated = false;
+    private boolean started = false;
+
+    public static final int START_DELAY = 5000;
+    public static final String PROPERTY_PREFIX = "camel.scr.properties.prefix";
+
+    // Configured fields
+    public String camelContextId = "camel-runner-default";
+    public boolean active = false;
+
+    public synchronized void activate(final BundleContext bundleContext, final 
Map<String, String> props) throws Exception {
+        if (activated) return;
+        log.debug("activated!");
+
+        activated = true;
+
+        prepare(bundleContext, props);
+
+        runWithDelay(this);
+    }
+
+    public synchronized void prepare(final BundleContext bundleContext, final 
Map<String, String> props) throws Exception {
+        createCamelContext(bundleContext, props);
+
+        // Configure fields from properties
+        configure(context, this, log);
+
+        setupCamelContext(bundleContext, camelContextId);
+    }
+
+    protected void createCamelContext(final BundleContext bundleContext, final 
Map<String, String> props) {
+        if (null != bundleContext) {
+            context = new OsgiDefaultCamelContext(bundleContext, registry);
+            // From https://issues.jboss.org/browse/MR-911
+            // Setup the application context classloader with the bundle 
classloader
+            context.setApplicationContextClassLoader(new 
BundleDelegatingClassLoader(bundleContext.getBundle()));
+            // and make sure the TCCL is our classloader
+            
Thread.currentThread().setContextClassLoader(context.getApplicationContextClassLoader());
+        } else {
+            context = new DefaultCamelContext(registry);
+        }
+        setupPropertiesComponent(context, props, log);
+    }
+
+    @SuppressWarnings("unused")
+    protected void setupCamelContext(final BundleContext bundleContext, final 
String camelContextId) throws Exception {
+        // Set up CamelContext
+        context.setNameStrategy(new 
ExplicitCamelContextNameStrategy(camelContextId));
+        context.setUseMDCLogging(true);
+        context.setUseBreadcrumb(true);
+
+        // Add routes
+        for (RoutesBuilder route : getRouteBuilders()) {
+            context.addRoutes(configure(context, route, log));
+        }
+    }
+
+    public static void setupPropertiesComponent(final CamelContext context, 
final Map<String, String> props, Logger log) {
+        // Set up PropertiesComponent
+        PropertiesComponent pc = new PropertiesComponent();
+        if (context.getComponentNames().contains("properties")) {
+            pc = context.getComponent("properties", PropertiesComponent.class);
+        } else {
+            context.addComponent("properties", pc);
+        }
+
+        // Set property prefix
+        if (null != System.getProperty(PROPERTY_PREFIX)) {
+            pc.setPropertyPrefix(System.getProperty(PROPERTY_PREFIX) + ".");
+        }
+
+        if (null != props) {
+            Properties initialProps = new Properties();
+            initialProps.putAll(props);
+            log.debug(String.format("Added %d initial properties", 
props.size()));
+            try {
+                pc.setInitialProperties(initialProps);
+            } catch (NoSuchMethodError e) {
+                // For Camel versions without setInitialProperties
+                pc.setOverrideProperties(initialProps);
+                pc.setLocation("default.properties");
+            }
+        }
+    }
+
+    protected abstract List<RoutesBuilder> getRouteBuilders();
+
+    // Run after a delay unless the method is called again
+    private void runWithDelay(final Runnable runnable) {
+        if (activated && !started) {
+            cancelDelayedRun();
+            // Run after a delay
+            starter = executor.schedule(runnable, START_DELAY, 
TimeUnit.MILLISECONDS);
+        }
+    }
+
+    private void cancelDelayedRun() {
+        if (null != starter) {
+            // Cancel but don't interrupt
+            starter.cancel(false);
+        }
+    }
+
+    public synchronized void run() {
+        startCamelContext();
+    }
+
+    public synchronized void deactivate() {
+        if (!activated) return;
+        log.debug("deactivated!");
+
+        activated = false;
+
+        cancelDelayedRun();
+
+        doDeactivate();
+
+        stopCamelContext();
+    }
+
+    protected void doDeactivate() {
+        stop();
+    }
+
+    public synchronized void stop() {
+        stopCamelContext();
+    }
+
+    private void startCamelContext() {
+        if (started) return;
+        try {
+            if (active) {
+                context.start();
+            } else {
+                log.info(camelContextId + " not started (active property is 
not true)");
+            }
+            started = true;
+        } catch (Exception e) {
+            log.error("Failed to start Camel context. Will try again when more 
Camel components have been registered.", e);
+        }
+    }
+
+    private void stopCamelContext() {
+        if (!started) return;
+        try {
+            context.stop();
+        } catch (Exception e) {
+            log.error("Failed to stop Camel context.", e);
+        } finally {
+            // Even if stopping failed we consider Camel context stopped
+            started = false;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public ModelCamelContext getContext() {
+        return context;
+    }
+
+    @SuppressWarnings("unused")
+    protected void gotCamelComponent(final ComponentResolver 
componentResolver) {
+        log.trace("Got a new Camel Component.");
+        runWithDelay(this);
+    }
+
+    @SuppressWarnings("unused")
+    protected void lostCamelComponent(final ComponentResolver 
componentResolver) {
+        log.trace("Lost a Camel Component.");
+    }
+
+    public static <T> T configure(final CamelContext context, final T target, 
final Logger log) {
+        Class clazz = target.getClass();
+        log.debug("Configuring " + clazz.getName());
+        Collection<Field> fields = new ArrayList<>();
+        fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
+        fields.addAll(Arrays.asList(clazz.getFields()));
+        for (Field field : fields) {
+            try {
+                String propertyValue = 
context.resolvePropertyPlaceholders("{{" + field.getName() + "}}");
+                if (!propertyValue.isEmpty()) {
+                    // Try to convert the value and set the field
+                    Object convertedValue = convertValue(propertyValue, 
field.getGenericType());
+                    ReflectionHelper.setField(field, target, convertedValue);
+                    log.debug("Set field " + field.getName() + " with value " 
+ propertyValue);
+                }
+            } catch (Exception e) {
+                log.debug("Field " + field.getName() + " skipped: " + 
e.getMessage());
+            }
+        }
+        return target;
+    }
+
+    public static Object convertValue(final String value, final Type type) 
throws Exception {
+        Class<?> clazz = null;
+        if (type instanceof ParameterizedType) {
+            clazz = (Class<?>) ((ParameterizedType) type).getRawType();
+        } else if (type instanceof Class) {
+            clazz = (Class) type;
+        }
+        if (null != value) {
+            if (clazz.isInstance(value)) {
+                return value;
+            } else if (clazz == String.class) {
+                return value;
+            } else if (clazz == Boolean.class || clazz == boolean.class) {
+                return Boolean.parseBoolean(value);
+            } else if (clazz == Integer.class || clazz == int.class) {
+                return Integer.parseInt(value);
+            } else if (clazz == Long.class || clazz == long.class) {
+                return Long.parseLong(value);
+            } else if (clazz == Double.class || clazz == double.class) {
+                return Double.parseDouble(value);
+            } else if (clazz == File.class) {
+                return new File(value);
+            } else if (clazz == URI.class) {
+                return new URI(value);
+            } else if (clazz == URL.class) {
+                return new URL(value);
+            } else {
+                throw new IllegalArgumentException("Unknown type: "+ (clazz != 
null ? clazz.getName() : null));
+            }
+        } else {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/components/camel-scr/src/main/java/org/apache/camel/scr/ScrHelper.java
----------------------------------------------------------------------
diff --git 
a/components/camel-scr/src/main/java/org/apache/camel/scr/ScrHelper.java 
b/components/camel-scr/src/main/java/org/apache/camel/scr/ScrHelper.java
new file mode 100644
index 0000000..759e605
--- /dev/null
+++ b/components/camel-scr/src/main/java/org/apache/camel/scr/ScrHelper.java
@@ -0,0 +1,80 @@
+package org.apache.camel.scr;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+@SuppressWarnings("unused")
+public class ScrHelper {
+
+    private static Logger log = LoggerFactory.getLogger(ScrHelper.class);
+
+    public static Map<String, String> getScrProperties(String componentName) 
throws Exception {
+        return 
getScrProperties(String.format("target/classes/OSGI-INF/%s.xml", 
componentName), componentName);
+    }
+
+    public static Map<String, String> getScrProperties(String xmlLocation, 
String componentName) throws Exception {
+        Map<String, String> result = new HashMap<>();
+        final Document dom = readXML(new File(xmlLocation));
+        final XPath xPath = 
XPathFactory.newInstance(XPathFactory.DEFAULT_OBJECT_MODEL_URI, 
"com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl", null).newXPath();
+        xPath.setNamespaceContext(new NamespaceContext() {
+            @Override
+            public String getNamespaceURI(String prefix) {
+                switch (prefix) {
+                    case "scr":
+                        try {
+                            XPathExpression scrNamespace = 
xPath.compile("/*/namespace::*[name()='scr']");
+                            Node node = (Node) scrNamespace.evaluate(dom, 
XPathConstants.NODE);
+                            return node.getNodeValue();
+                        } catch (XPathExpressionException e) {
+                            e.printStackTrace();
+                        }
+                        return "http://www.osgi.org/xmlns/scr/v1.1.0";;
+                }
+                return XMLConstants.NULL_NS_URI;
+            }
+
+            @Override
+            public String getPrefix(String namespaceURI) {
+                return null;
+            }
+
+            @Override
+            public Iterator getPrefixes(String namespaceURI) {
+                return null;
+            }
+        });
+        String propertyListExpression = 
String.format("/components/scr:component[@name='%s']/property", componentName);
+        XPathExpression propertyList = xPath.compile(propertyListExpression);
+        XPathExpression propertyName = xPath.compile("@name");
+        XPathExpression propertyValue = xPath.compile("@value");
+        NodeList nodes = (NodeList) propertyList.evaluate(dom, 
XPathConstants.NODESET);
+        for (int i = 0; i < nodes.getLength(); i++) {
+            Node node = nodes.item(i);
+            result.put((String) propertyName.evaluate(node, 
XPathConstants.STRING), (String) propertyValue.evaluate(node, 
XPathConstants.STRING));
+        }
+        return result;
+    }
+
+    private static Document readXML(File xml) throws 
ParserConfigurationException, SAXException, IOException {
+        DocumentBuilderFactory builderFactory = 
DocumentBuilderFactory.newInstance();
+        builderFactory.setNamespaceAware(true);
+        DocumentBuilder builder = builderFactory.newDocumentBuilder();
+        return builder.parse(xml);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/components/camel-scr/src/test/java/org/apache/camel/scr/AbstractCamelRunnerTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-scr/src/test/java/org/apache/camel/scr/AbstractCamelRunnerTest.java
 
b/components/camel-scr/src/test/java/org/apache/camel/scr/AbstractCamelRunnerTest.java
new file mode 100644
index 0000000..93fab09
--- /dev/null
+++ 
b/components/camel-scr/src/test/java/org/apache/camel/scr/AbstractCamelRunnerTest.java
@@ -0,0 +1,105 @@
+package org.apache.camel.scr;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(JUnit4.class)
+public class AbstractCamelRunnerTest {
+
+    Logger log = LoggerFactory.getLogger(getClass());
+
+    @Rule
+    public TestName testName = new TestName();
+
+    @Before
+    public void setUp() throws Exception {
+        
log.info("*******************************************************************");
+        log.info("Test: " + testName.getMethodName());
+        
log.info("*******************************************************************");
+    }
+
+    @Test
+    public void testActivateDeactivate() {
+        ConcreteCamelRunner integration = new ConcreteCamelRunner();
+        try {
+            integration.activate(null, integration.getDefaultProperties());
+            Thread.sleep(ConcreteCamelRunner.START_DELAY + 1000);
+            integration.deactivate();
+            assertTrue("Camel context has not started.", 
integration.camelContextStarted == 1);
+            assertTrue("Camel context has not stopped.", 
integration.camelContextStopped == 1);
+            assertTrue("Not enough routes added.", integration.routeAdded == 
2);
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+    @Test
+    public void testPrepareRunStop() {
+        ConcreteCamelRunner integration = new ConcreteCamelRunner();
+        try {
+            integration.prepare(null, integration.getDefaultProperties());
+            integration.run();
+            do {
+                Thread.sleep(500);
+            } while (integration.getContext().isStartingRoutes());
+            integration.stop();
+            assertTrue("Camel context has not started.", 
integration.camelContextStarted == 1);
+            assertTrue("Camel context has not stopped.", 
integration.camelContextStopped == 1);
+            assertTrue("Not enough routes added.", integration.routeAdded == 
2);
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+    @Test
+    public void testDelayedStart() {
+        ConcreteCamelRunner integration = new ConcreteCamelRunner();
+        try {
+            integration.activate(null, integration.getDefaultProperties());
+            Thread.sleep(2000);
+            integration.gotCamelComponent(null);
+            Thread.sleep(ConcreteCamelRunner.START_DELAY - 1000);
+            assertTrue("Camel context has started too early", 
integration.camelContextStarted == 0);
+            Thread.sleep(2000);
+            assertTrue("Camel context has not started.", 
integration.camelContextStarted == 1);
+            integration.deactivate();
+            assertTrue("Camel context has not stopped.", 
integration.camelContextStopped == 1);
+            assertTrue("Not enough routes added.", integration.routeAdded == 
2);
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+    @Test
+    public void testDelayedStartCancel() {
+        ConcreteCamelRunner integration = new ConcreteCamelRunner();
+
+        Map<String, String> properties = integration.getDefaultProperties();
+        properties.put("from", "notfound:something");
+        properties.put("camelroute.id", "test/notfound-mock");
+
+        try {
+            integration.activate(null, properties);
+            Thread.sleep(ConcreteCamelRunner.START_DELAY - 1000);
+            integration.deactivate();
+            assertTrue("Routes have been added.", integration.routeAdded == 0);
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/components/camel-scr/src/test/java/org/apache/camel/scr/ConcreteCamelRunner.java
----------------------------------------------------------------------
diff --git 
a/components/camel-scr/src/test/java/org/apache/camel/scr/ConcreteCamelRunner.java
 
b/components/camel-scr/src/test/java/org/apache/camel/scr/ConcreteCamelRunner.java
new file mode 100644
index 0000000..ae3651f
--- /dev/null
+++ 
b/components/camel-scr/src/test/java/org/apache/camel/scr/ConcreteCamelRunner.java
@@ -0,0 +1,98 @@
+package org.apache.camel.scr;
+
+import org.apache.camel.*;
+import org.apache.camel.spi.LifecycleStrategy;
+import org.apache.camel.spi.RouteContext;
+import org.osgi.framework.BundleContext;
+
+import java.util.*;
+import java.util.concurrent.ThreadPoolExecutor;
+
+public class ConcreteCamelRunner extends AbstractCamelRunner implements 
LifecycleStrategy {
+
+    protected int camelContextStarted = 0;
+    protected int camelContextStopped = 0;
+    protected int routeAdded = 0;
+
+    public Map<String, String> getDefaultProperties() {
+        // Set default properties
+        Map<String,String> defaultProps = new HashMap<>();
+        defaultProps.put("camelContextId", "camel-runner-test");
+        defaultProps.put("camelRouteId", "test/direct-mock");
+        defaultProps.put("active", "true");
+        defaultProps.put("from", "direct:start");
+        defaultProps.put("to", "mock:end");
+        defaultProps.put("messageOk", "Success");
+        defaultProps.put("messageError", "Failure");
+        defaultProps.put("maximumRedeliveries", "0");
+        defaultProps.put("redeliveryDelay", "1000");
+        defaultProps.put("backOffMultiplier", "2");
+        defaultProps.put("maximumRedeliveryDelay", "60000");
+        return defaultProps;
+    }
+
+    @Override
+    protected void createCamelContext(BundleContext bundleContext, Map<String, 
String> props) {
+        super.createCamelContext(bundleContext, props);
+        context.addLifecycleStrategy(this);
+    }
+
+    @Override
+    public List<RoutesBuilder> getRouteBuilders() {
+        List<RoutesBuilder> routesBuilders = new ArrayList<>();
+        routesBuilders.add(new TestRouteBuilder());
+        routesBuilders.add(new TestRouteBuilder2());
+        return routesBuilders;
+    }
+
+    @Override
+    public void onContextStart(CamelContext camelContext) throws 
VetoCamelContextStartException {
+        camelContextStarted++;
+    }
+
+    @Override
+    public void onContextStop(CamelContext camelContext) {
+        camelContextStopped++;
+    }
+
+    @Override
+    public void onComponentAdd(String s, Component component) {}
+
+    @Override
+    public void onComponentRemove(String s, Component component) {}
+
+    @Override
+    public void onEndpointAdd(Endpoint endpoint) {}
+
+    @Override
+    public void onEndpointRemove(Endpoint endpoint) {}
+
+    @Override
+    public void onServiceAdd(CamelContext camelContext, Service service, Route 
route) {}
+
+    @Override
+    public void onServiceRemove(CamelContext camelContext, Service service, 
Route route) {}
+
+    @Override
+    public void onRoutesAdd(Collection<Route> routes) {
+        routeAdded++;
+    }
+
+    @Override
+    public void onRoutesRemove(Collection<Route> routes) {}
+
+    @Override
+    public void onRouteContextCreate(RouteContext routeContext) {}
+
+    @Override
+    public void onErrorHandlerAdd(RouteContext routeContext, Processor 
processor, ErrorHandlerFactory errorHandlerFactory) {}
+
+    @Override
+    public void onErrorHandlerRemove(RouteContext routeContext, Processor 
processor, ErrorHandlerFactory errorHandlerFactory) {}
+
+    @Override
+    public void onThreadPoolAdd(CamelContext camelContext, ThreadPoolExecutor 
threadPoolExecutor, String s, String s2, String s3, String s4) {}
+
+    @Override
+    public void onThreadPoolRemove(CamelContext camelContext, 
ThreadPoolExecutor threadPoolExecutor) {}
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/components/camel-scr/src/test/java/org/apache/camel/scr/TestRouteBuilder.java
----------------------------------------------------------------------
diff --git 
a/components/camel-scr/src/test/java/org/apache/camel/scr/TestRouteBuilder.java 
b/components/camel-scr/src/test/java/org/apache/camel/scr/TestRouteBuilder.java
new file mode 100644
index 0000000..806692f
--- /dev/null
+++ 
b/components/camel-scr/src/test/java/org/apache/camel/scr/TestRouteBuilder.java
@@ -0,0 +1,43 @@
+package org.apache.camel.scr;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.commons.lang.Validate;
+
+public class TestRouteBuilder extends RouteBuilder {
+
+    // Configured fields
+    @SuppressWarnings("unused")
+    private Integer maximumRedeliveries;
+    @SuppressWarnings("unused")
+    private Long redeliveryDelay;
+    @SuppressWarnings("unused")
+    private Double backOffMultiplier;
+    @SuppressWarnings("unused")
+    private Long maximumRedeliveryDelay;
+    @SuppressWarnings("unused")
+    private String camelRouteId;
+
+    @Override
+    public void configure() throws Exception {
+        checkProperties();
+
+        errorHandler(defaultErrorHandler()
+                .maximumRedeliveries(maximumRedeliveries)
+                .redeliveryDelay(redeliveryDelay)
+                .backOffMultiplier(backOffMultiplier)
+                .maximumRedeliveryDelay(maximumRedeliveryDelay));
+
+        from("{{from}}")
+                .routeId(camelRouteId)
+                .log("{{messageOk}}")
+                .to("{{to}}");
+    }
+
+    public void checkProperties() {
+        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");
+        Validate.notNull(camelRouteId, "camelRouteId property is not set");
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/components/camel-scr/src/test/java/org/apache/camel/scr/TestRouteBuilder2.java
----------------------------------------------------------------------
diff --git 
a/components/camel-scr/src/test/java/org/apache/camel/scr/TestRouteBuilder2.java
 
b/components/camel-scr/src/test/java/org/apache/camel/scr/TestRouteBuilder2.java
new file mode 100644
index 0000000..8a638db
--- /dev/null
+++ 
b/components/camel-scr/src/test/java/org/apache/camel/scr/TestRouteBuilder2.java
@@ -0,0 +1,13 @@
+package org.apache.camel.scr;
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class TestRouteBuilder2 extends RouteBuilder {
+    @Override
+    public void configure() throws Exception {
+        from("direct://start2")
+                .routeId("Second")
+                .log("{{messageOk}}")
+                .to("{{to}}");
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/components/camel-scr/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/components/camel-scr/src/test/resources/log4j.properties 
b/components/camel-scr/src/test/resources/log4j.properties
new file mode 100644
index 0000000..0038efe
--- /dev/null
+++ b/components/camel-scr/src/test/resources/log4j.properties
@@ -0,0 +1,18 @@
+
+#
+# The logging properties used
+#
+log4j.rootLogger=INFO, out
+
+# uncomment the following line to turn on Camel debugging
+#log4j.logger.org.apache.camel=DEBUG
+
+log4j.logger.com.github.yuruki=DEBUG
+
+# CONSOLE appender not used by default
+log4j.appender.out=org.apache.log4j.ConsoleAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=[%30.30t] %-30.30c{1} %-5p %m%n
+#log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - 
%m%n
+
+log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/components/pom.xml
----------------------------------------------------------------------
diff --git a/components/pom.xml b/components/pom.xml
index e8810d1..f18e37c 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -175,6 +175,7 @@
     <module>camel-saxon</module>
     <module>camel-salesforce</module>
     <module>camel-schematron</module>
+    <module>camel-scr</module>
     <module>camel-script</module>
     <module>camel-servlet</module>
     <module>camel-servletlistener</module>

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/parent/pom.xml
----------------------------------------------------------------------
diff --git a/parent/pom.xml b/parent/pom.xml
index c3131d9..5fb0bc5 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -143,6 +143,7 @@
     <felix-configadmin-version>1.4.0</felix-configadmin-version>
     <felix-fileinstall-version>3.2.6</felix-fileinstall-version>
     <felix-framework-version>3.2.2</felix-framework-version>
+    <felix-scr-annotations-version>1.9.8</felix-scr-annotations-version>
     <findbugs-maven-plugin-version>2.5.2</findbugs-maven-plugin-version>
     <flatpack-version>3.4.2</flatpack-version>
     <fop-bundle-version>1.1_1</fop-bundle-version>

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/tooling/archetypes/camel-archetype-scr/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/archetypes/camel-archetype-scr/pom.xml 
b/tooling/archetypes/camel-archetype-scr/pom.xml
new file mode 100644
index 0000000..11782fb
--- /dev/null
+++ b/tooling/archetypes/camel-archetype-scr/pom.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<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/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>archetypes</artifactId>
+        <groupId>org.apache.camel</groupId>
+        <version>2.15-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.camel.archetypes</groupId>
+    <artifactId>camel-archetype-scr</artifactId>
+    <name>Camel :: Archetypes :: OSGi Service Component Runtime bundle</name>
+    <description>Creates a new Camel project with OSGi Service Component 
Runtime support.</description>
+    <packaging>maven-archetype</packaging>
+
+    <properties>
+        <jboss-fuse-version>6.1.0.redhat-379</jboss-fuse-version>
+    </properties>
+
+    <build>
+        <extensions>
+            <extension>
+                <groupId>org.apache.maven.archetype</groupId>
+                <artifactId>archetype-packaging</artifactId>
+                <version>2.2</version>
+            </extension>
+        </extensions>
+
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>false</filtering>
+            </resource>
+            <resource>
+                <directory>src/main/resources-filtered</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/archetype-metadata.xml</include>
+                </includes>
+            </resource>
+        </resources>
+
+        <testResources>
+            <testResource>
+                <directory>src/test/resources</directory>
+                <filtering>true</filtering>
+            </testResource>
+        </testResources>
+
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <artifactId>maven-archetype-plugin</artifactId>
+                    <version>2.2</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/tooling/archetypes/camel-archetype-scr/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
----------------------------------------------------------------------
diff --git 
a/tooling/archetypes/camel-archetype-scr/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
 
b/tooling/archetypes/camel-archetype-scr/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
new file mode 100644
index 0000000..f7c4bee
--- /dev/null
+++ 
b/tooling/archetypes/camel-archetype-scr/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archetype-descriptor 
xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0
 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd"; 
name="finavia-blueprint"
+                      
xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0";
+                      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";>
+    <requiredProperties>
+        <requiredProperty key="archetypeGroupId">
+            <defaultValue>${project.groupId}</defaultValue>
+        </requiredProperty>
+        <requiredProperty key="archetypeArtifactId">
+            <defaultValue>${project.artifactId}</defaultValue>
+        </requiredProperty>
+        <requiredProperty key="archetypeVersion">
+            <defaultValue>${project.version}</defaultValue>
+        </requiredProperty>
+        <requiredProperty key="groupId"/>
+        <requiredProperty key="className"/>
+        <requiredProperty key="jboss-fuse-version">
+            <defaultValue>${jboss-fuse-version}</defaultValue>
+        </requiredProperty>
+    </requiredProperties>
+    <fileSets>
+        <fileSet filtered="true" packaged="true" encoding="UTF-8">
+            <directory>src/main/java</directory>
+            <includes>
+                <include>**/*.java</include>
+            </includes>
+        </fileSet>
+        <fileSet filtered="true" encoding="UTF-8">
+            <directory>src/main/resources</directory>
+            <includes>
+                <include>**/*</include>
+            </includes>
+        </fileSet>
+        <fileSet filtered="true" packaged="true" encoding="UTF-8">
+            <directory>src/test/java</directory>
+            <includes>
+                <include>**/*.java</include>
+            </includes>
+        </fileSet>
+        <fileSet filtered="true" encoding="UTF-8">
+            <directory>src/test/resources</directory>
+            <includes>
+                <include>**/*</include>
+            </includes>
+        </fileSet>
+    </fileSets>
+</archetype-descriptor>

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/pom.xml
----------------------------------------------------------------------
diff --git 
a/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/pom.xml
 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/pom.xml
new file mode 100644
index 0000000..46c0581
--- /dev/null
+++ 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/pom.xml
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+This file was generated from 
${archetypeGroupId}/${archetypeArtifactId}/${archetypeVersion}
+-->
+<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";>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>${groupId}</groupId>
+    <artifactId>${artifactId}</artifactId>
+    <packaging>bundle</packaging>
+    <version>${version}</version>
+
+    <name>${project.artifactId}</name>
+    <url>http://www.myorganization.org</url>
+
+    <scm>
+        <connection>${my.scm.url}/${project.artifactId}.git</connection>
+        
<developerConnection>${my.scm.url}/${project.artifactId}.git</developerConnection>
+        <tag>HEAD</tag>
+    </scm>
+
+    <prerequisites>
+        <maven>3.0.4</maven>
+    </prerequisites>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+    </properties>
+
+    <distributionManagement>
+        <repository>
+            <id>release_deployment</id>
+            <name>Internal Releases</name>
+            <url>${my.release.url}</url>
+        </repository>
+        <snapshotRepository>
+            <id>snapshot_deployment</id>
+            <name>Internal Snapshots</name>
+            <url>${my.snapshot.url}</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <repositories>
+        <repository>
+            <id>fusesource.m2</id>
+            <name>JBoss FS Public Repository Group</name>
+            <url>https://repo.fusesource.com/nexus/content/groups/public</url>
+            <layout>default</layout>
+            <releases>
+                <enabled>true</enabled>
+                <updatePolicy>never</updatePolicy>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <!-- This gives us the versions of Fuse components -->
+                <groupId>org.jboss.fuse.bom</groupId>
+                <artifactId>jboss-fuse-parent</artifactId>
+                <version>${jboss-fuse-version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <!-- camel-core-osgi doesn't seem to be included in the above 
bill of materials -->
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-core-osgi</artifactId>
+                <version>${archetypeVersion}</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-io</groupId>
+                <artifactId>commons-io</artifactId>
+                <version>2.4</version>
+            </dependency>
+            <dependency>
+                <groupId>com.jayway.restassured</groupId>
+                <artifactId>rest-assured</artifactId>
+                <version>2.3.0</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core</artifactId>
+            <version>${archetypeVersion}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-scr</artifactId>
+            <version>${archetypeVersion}</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+        </dependency>
+
+        <!-- logging -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.jayway.restassured</groupId>
+            <artifactId>rest-assured</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.1</version>
+                <configuration>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <version>2.6</version>
+                <configuration>
+                    <encoding>UTF-8</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+                <version>2.3</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>2.9.1</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-release-plugin</artifactId>
+                <version>2.5</version>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.maven.scm</groupId>
+                        <artifactId>maven-scm-provider-gitexe</artifactId>
+                        <version>1.9</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>versions-maven-plugin</artifactId>
+                <version>2.1</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+                <version>1.19.0</version>
+                <executions>
+                    <execution>
+                        <id>generate-scr-scrdescriptor</id>
+                        <phase>compile</phase>
+                        <goals>
+                            <goal>scr</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>2.4.0</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Gravia-Enabled>true</Gravia-Enabled>
+                        <Export-Package/>
+                        <Private-Package>
+                            ${groupId},
+                            ${groupId}.*,
+                            ${archetypeGroupId}
+                        </Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/java/__className__.java
----------------------------------------------------------------------
diff --git 
a/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/java/__className__.java
 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/java/__className__.java
new file mode 100644
index 0000000..45156fd
--- /dev/null
+++ 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/java/__className__.java
@@ -0,0 +1,47 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+// This file was generated from 
${archetypeGroupId}/${archetypeArtifactId}/${archetypeVersion}
+package ${groupId};
+
+import org.apache.camel.scr.AbstractCamelRunner;
+import ${groupId}.internal.${className}Route;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.spi.ComponentResolver;
+import org.apache.felix.scr.annotations.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Component(label = ${className}.COMPONENT_LABEL, description = 
${className}.COMPONENT_DESCRIPTION, immediate = true, metatype = true)
+@Properties({
+        @Property(name = "camelContextId", value = "${artifactId}"),
+        @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 = "summaryLogging", value = "false"),
+        @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 ${className} extends AbstractCamelRunner {
+
+    public static final String COMPONENT_LABEL = "${groupId}.${className}";
+    public static final String COMPONENT_DESCRIPTION = "This is the current 
configuration for ${artifactId}.";
+
+    @Override
+    protected List<RoutesBuilder>getRouteBuilders() {
+        List<RoutesBuilder>routesBuilders = new ArrayList<>();
+        routesBuilders.add(new ${className}Route(registry));
+        return routesBuilders;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/java/internal/__className__Route.java
----------------------------------------------------------------------
diff --git 
a/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/java/internal/__className__Route.java
 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/java/internal/__className__Route.java
new file mode 100644
index 0000000..f0e51ce
--- /dev/null
+++ 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/java/internal/__className__Route.java
@@ -0,0 +1,79 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+// This file was generated from 
${archetypeGroupId}/${archetypeArtifactId}/${archetypeVersion}
+package ${groupId}.internal;
+
+import org.apache.camel.LoggingLevel;
+import org.apache.camel.builder.PredicateBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.SimpleRegistry;
+import org.apache.commons.lang.Validate;
+
+public class ${className}Route extends RouteBuilder {
+
+    SimpleRegistry registry;
+
+    // Configured fields
+    @SuppressWarnings("unused")
+    private String camelRouteId;
+    @SuppressWarnings("unused")
+    private Integer maximumRedeliveries;
+    @SuppressWarnings("unused")
+    private Long redeliveryDelay;
+    @SuppressWarnings("unused")
+    private Double backOffMultiplier;
+    @SuppressWarnings("unused")
+    private Long maximumRedeliveryDelay;
+    protected boolean summaryLogging = false;
+
+    public ${className}Route(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("*", "breadcrumbId")
+            .to("{{to}}");
+
+        from("direct:processCompletion")
+            .startupOrder(1)
+            .routeId(camelRouteId + ".completion")
+            .choice()
+                .when(PredicateBuilder.and(simple("${exception} == null"), 
PredicateBuilder.constant(summaryLogging)))
+                    .to("log:" + camelRouteId +".success?groupInterval=60000")
+                .when(PredicateBuilder.and(simple("${exception} == null"), 
PredicateBuilder.constant(!summaryLogging)))
+                    .log("{{messageOk}}")
+                .when(PredicateBuilder.constant(summaryLogging))
+                    .to("log:" + camelRouteId +".failure?groupInterval=60000")
+                .otherwise()
+                    .log(LoggingLevel.ERROR, "{{messageError}}")
+            .endChoice();
+       }
+
+    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");
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/resources/default.properties
----------------------------------------------------------------------
diff --git 
a/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/resources/default.properties
 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/resources/default.properties
new file mode 100644
index 0000000..cf60124
--- /dev/null
+++ 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/resources/default.properties
@@ -0,0 +1 @@
+dummy = dummy
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/resources/log4j.properties
----------------------------------------------------------------------
diff --git 
a/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/resources/log4j.properties
 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/resources/log4j.properties
new file mode 100644
index 0000000..805421c
--- /dev/null
+++ 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/main/resources/log4j.properties
@@ -0,0 +1,17 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+${symbol_pound}
+${symbol_pound} The logging properties used
+${symbol_pound}
+log4j.rootLogger=INFO, out
+
+${symbol_pound} uncomment the following line to turn on Camel debugging
+${symbol_pound}log4j.logger.org.apache.camel=DEBUG
+
+${symbol_pound} CONSOLE appender not used by default
+log4j.appender.out=org.apache.log4j.ConsoleAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=[%30.30t] %-30.30c{1} %-5p %m%n
+${symbol_pound}log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p 
%-30.30c{1} - %m%n
+

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/test/java/__className__Test.java
----------------------------------------------------------------------
diff --git 
a/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/test/java/__className__Test.java
 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/test/java/__className__Test.java
new file mode 100644
index 0000000..044c6ba
--- /dev/null
+++ 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/test/java/__className__Test.java
@@ -0,0 +1,103 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+// This file was generated from 
${archetypeGroupId}/${archetypeArtifactId}/${archetypeVersion}
+package ${groupId};
+
+import org.apache.camel.scr.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.apache.commons.io.IOUtils;
+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;
+
+import java.util.List;
+
+import static com.jayway.restassured.RestAssured.*;
+import static com.jayway.restassured.matcher.RestAssuredMatchers.*;
+import static org.hamcrest.Matchers.*;
+
+@RunWith(JUnit4.class)
+public class ${className}Test {
+
+    Logger log = LoggerFactory.getLogger(getClass());
+
+    @Rule
+    public TestName testName = new TestName();
+
+    ${className} 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(${className}.PROPERTY_PREFIX, "unit");
+
+        // Prepare the integration
+        integration = new ${className}();
+        integration.prepare(null, 
ScrHelper.getScrProperties(integration.getClass().getName()));
+        context = integration.getContext();
+
+        // 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
+                mockEndpointsAndSkip("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
+
+        // You can also take the expected result from an external file
+        // String result = 
IOUtils.toString(context.getClassResolver().loadResourceAsStream("testdata/out/result.txt"));
+        // resultEndpoint.expectedBodiesReceived(result.replaceAll("\r?\n", 
"\n"));
+
+        // Start the integration
+        integration.run();
+
+        // Send the test message
+        context.createProducerTemplate().sendBody("direct:start", "hello");
+
+        // You can also send an external file
+        // context.createProducerTemplate.sendBody("direct:start", 
context.getClassResolver().loadResourceAsStream("testdata/in/input.xml"));
+
+        // REST/HTTP services can be easily tested with RestAssured:
+        // 
get(context.resolvePropertyPlaceholders("{{restUrl}}")).then().statusCode(204).body(isEmptyOrNullString());
+        // 
given().param("status").get(context.resolvePropertyPlaceholders("{{restUrl}}")).then().statusCode(200).body(equalTo("active"));
+        // given().auth().basic("testuser", 
"testpass").body("hello").when().post(context.resolvePropertyPlaceholders("{{restUrl}}")).then().statusCode(200).body(equalTo("response"));
+
+        resultEndpoint.assertIsSatisfied();
+       }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git 
a/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/test/resources/log4j.properties
 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/test/resources/log4j.properties
new file mode 100644
index 0000000..4f48633
--- /dev/null
+++ 
b/tooling/archetypes/camel-archetype-scr/src/main/resources/archetype-resources/src/test/resources/log4j.properties
@@ -0,0 +1,12 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+${symbol_pound} CONSOLE appender not used by default
+log4j.rootLogger=INFO, out
+${symbol_pound}log4j.logger.org.apache.camel=DEBUG
+log4j.logger.${groupId}=DEBUG
+log4j.appender.out=org.apache.log4j.ConsoleAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=[%30.30t] %-30.30c{1} %-5p %m%n
+${symbol_pound}log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p 
%-30.30c{1} - %m%n
+

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/tooling/archetypes/camel-archetype-scr/src/test/resources/projects/camel-scr-example/archetype.properties
----------------------------------------------------------------------
diff --git 
a/tooling/archetypes/camel-archetype-scr/src/test/resources/projects/camel-scr-example/archetype.properties
 
b/tooling/archetypes/camel-archetype-scr/src/test/resources/projects/camel-scr-example/archetype.properties
new file mode 100644
index 0000000..c6adb9f
--- /dev/null
+++ 
b/tooling/archetypes/camel-archetype-scr/src/test/resources/projects/camel-scr-example/archetype.properties
@@ -0,0 +1,9 @@
+groupId = example
+artifactId = camel-scr-example
+version = 1.0-SNAPSHOT
+package = example
+className = CamelScrExample
+archetypeGroupId = ${project.groupId}
+archetypeArtifactId = ${project.artifactId}
+archetypeVersion = ${project.version}
+jboss-fuse-version = ${jboss-fuse-version}

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/tooling/archetypes/camel-archetype-scr/src/test/resources/projects/camel-scr-example/goal.txt
----------------------------------------------------------------------
diff --git 
a/tooling/archetypes/camel-archetype-scr/src/test/resources/projects/camel-scr-example/goal.txt
 
b/tooling/archetypes/camel-archetype-scr/src/test/resources/projects/camel-scr-example/goal.txt
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ 
b/tooling/archetypes/camel-archetype-scr/src/test/resources/projects/camel-scr-example/goal.txt
@@ -0,0 +1 @@
+test
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/d742358e/tooling/archetypes/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/archetypes/pom.xml b/tooling/archetypes/pom.xml
index 4839410..8fe7c77 100644
--- a/tooling/archetypes/pom.xml
+++ b/tooling/archetypes/pom.xml
@@ -42,6 +42,7 @@
     <module>camel-archetype-groovy</module>
     <module>camel-archetype-java</module>
     <module>camel-archetype-scala</module>
+    <module>camel-archetype-scr</module>
     <module>camel-archetype-spring</module>
     <module>camel-archetype-spring-dm</module>
     <module>camel-archetype-web</module>

Reply via email to