You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/02/19 16:01:13 UTC

git commit: [KARAF-2763] Use a plugin for SCR support to work around the fact that maven can't add build artifacts to plugin class path

Repository: karaf
Updated Branches:
  refs/heads/master 92c85f25c -> 73205de0d


[KARAF-2763] Use a plugin for SCR support to work around the fact that maven can't add build artifacts to plugin class path

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

Branch: refs/heads/master
Commit: 73205de0d50e91990c04674351e45797d6ee7e76
Parents: 92c85f2
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Wed Feb 19 16:00:59 2014 +0100
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Wed Feb 19 16:00:59 2014 +0100

----------------------------------------------------------------------
 pom.xml                                         |  17 +-
 scr/command/pom.xml                             |  23 +-
 scr/pom.xml                                     |   1 -
 scr/support/pom.xml                             | 113 -------
 .../karaf/scr/support/InjectAnnotations.java    | 279 -----------------
 .../karaf/scr/support/ScrCommandSupport.java    | 112 -------
 tooling/karaf-scr-maven-plugin/pom.xml          | 243 +++++++++++++++
 .../karaf/tooling/scr/ScrCommandMojo.java       | 309 +++++++++++++++++++
 .../karaf/tooling/scr/ScrCommandSupport.java    | 112 +++++++
 tooling/pom.xml                                 |   1 +
 10 files changed, 685 insertions(+), 525 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/73205de0/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index da53fad..e1780ac 100644
--- a/pom.xml
+++ b/pom.xml
@@ -59,9 +59,7 @@
         <module>webconsole</module>
         <module>exception</module>
         <module>scheduler</module>
-		<!--
         <module>scr</module>
-		-->
         <module>diagnostic</module>
         <module>obr</module>
         <module>jndi</module>
@@ -1930,6 +1928,21 @@
                     </configuration>
                 </plugin>
                 <plugin>
+                    <groupId>org.apache.karaf.tooling</groupId>
+                    <artifactId>karaf-scr-maven-plugin</artifactId>
+                    <version>${project.version}</version>
+                    <executions>
+                        <execution>
+                            <goals>
+                                <goal>scr</goal>
+                            </goals>
+                            <configuration>
+                                <ranking>${karaf.service.ranking}</ranking>
+                            </configuration>
+                        </execution>
+                    </executions>
+                </plugin>
+                <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-idea-plugin</artifactId>
                     <version>2.2.1</version>

http://git-wip-us.apache.org/repos/asf/karaf/blob/73205de0/scr/command/pom.xml
----------------------------------------------------------------------
diff --git a/scr/command/pom.xml b/scr/command/pom.xml
index 4475bfc..1a8a981 100644
--- a/scr/command/pom.xml
+++ b/scr/command/pom.xml
@@ -35,6 +35,7 @@
 
     <properties>
         <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
+        <karaf.service.ranking>1</karaf.service.ranking>
     </properties>
 
     <dependencies>
@@ -69,11 +70,6 @@
             <artifactId>bndlib</artifactId>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.karaf.scr</groupId>
-            <artifactId>org.apache.karaf.scr.support</artifactId>
-            <scope>provided</scope>
-        </dependency>
     </dependencies>
 
     <build>
@@ -94,21 +90,12 @@
         </resources>
         <plugins>
             <plugin>
+                <groupId>org.apache.karaf.tooling</groupId>
+                <artifactId>karaf-scr-maven-plugin</artifactId>
+           </plugin>
+            <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
-                <configuration>
-                    <instructions>
-                        <Service-Component>*</Service-Component>
-                        <_plugin>org.apache.karaf.scr.support.InjectAnnotations</_plugin>
-                    </instructions>
-                </configuration>
-                <dependencies>
-                    <dependency>
-                        <groupId>org.apache.karaf.scr</groupId>
-                        <artifactId>org.apache.karaf.scr.support</artifactId>
-                        <version>${project.version}</version>
-                    </dependency>
-                </dependencies>
             </plugin>
         </plugins>
     </build>

http://git-wip-us.apache.org/repos/asf/karaf/blob/73205de0/scr/pom.xml
----------------------------------------------------------------------
diff --git a/scr/pom.xml b/scr/pom.xml
index 4d7422c..162477a 100644
--- a/scr/pom.xml
+++ b/scr/pom.xml
@@ -34,7 +34,6 @@
     <name>Apache Karaf :: Declarative Services (DS)</name>
 
     <modules>
-        <module>support</module>
         <module>command</module>
         <module>management</module>
         <module>examples</module>

http://git-wip-us.apache.org/repos/asf/karaf/blob/73205de0/scr/support/pom.xml
----------------------------------------------------------------------
diff --git a/scr/support/pom.xml b/scr/support/pom.xml
deleted file mode 100644
index 3ee6706..0000000
--- a/scr/support/pom.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<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">
-
-    <!--
-
-        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.
-    -->
-
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.karaf.scr</groupId>
-        <artifactId>scr</artifactId>
-        <version>3.0.1-SNAPSHOT</version>
-        <relativePath>../pom.xml</relativePath>
-    </parent>
-
-    <artifactId>org.apache.karaf.scr.support</artifactId>
-    <packaging>jar</packaging>
-    <name>Apache Karaf :: SCR :: Support</name>
-    <description>This bundle provides support for commands.</description>
-
-    <properties>
-        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.core</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.karaf.shell</groupId>
-            <artifactId>org.apache.karaf.shell.console</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.scr</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>biz.aQute.bnd</groupId>
-            <artifactId>bndlib</artifactId>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.gogo.runtime</artifactId>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <resources>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <includes>
-                    <include>**/*</include>
-                </includes>
-            </resource>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <filtering>true</filtering>
-                <includes>
-                    <include>**/*.info</include>
-                </includes>
-            </resource>
-        </resources>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <configuration>
-                    <instructions>
-                        <Import-Package>
-                            org.apache.felix.gogo.commands,
-                            org.apache.karaf.shell.commands.basic,
-                            org.apache.karaf.shell.console,
-                            org.apache.karaf.shell.inject,
-                            org.osgi.framework,
-                            org.osgi.service.component,
-                            org.slf4j
-                        </Import-Package>
-                        <Export-Package>
-                            org.apache.karaf.scr.support
-                        </Export-Package>
-                        <Private-Package>
-                            org.apache.karaf.scr.support.plugin
-                        </Private-Package>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/73205de0/scr/support/src/main/java/org/apache/karaf/scr/support/InjectAnnotations.java
----------------------------------------------------------------------
diff --git a/scr/support/src/main/java/org/apache/karaf/scr/support/InjectAnnotations.java b/scr/support/src/main/java/org/apache/karaf/scr/support/InjectAnnotations.java
deleted file mode 100644
index 92e56b1..0000000
--- a/scr/support/src/main/java/org/apache/karaf/scr/support/InjectAnnotations.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * 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.
- */
-package org.apache.karaf.scr.support;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import aQute.bnd.component.HeaderReader;
-import aQute.bnd.component.TagResource;
-import aQute.bnd.header.Parameters;
-import aQute.bnd.osgi.Analyzer;
-import aQute.bnd.osgi.Annotation;
-import aQute.bnd.osgi.ClassDataCollector;
-import aQute.bnd.osgi.Clazz;
-import aQute.bnd.osgi.Constants;
-import aQute.bnd.osgi.Descriptors;
-import aQute.bnd.osgi.Instruction;
-import aQute.bnd.osgi.Processor;
-import aQute.bnd.osgi.URLResource;
-import aQute.bnd.service.AnalyzerPlugin;
-import aQute.lib.tag.Tag;
-import org.apache.felix.service.command.CommandProcessor;
-import org.apache.felix.service.command.Function;
-import org.apache.karaf.scr.support.ScrCommandSupport;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.CommandWithAction;
-import org.apache.karaf.shell.commands.basic.AbstractCommand;
-import org.apache.karaf.shell.console.CompletableFunction;
-import org.apache.karaf.shell.inject.Destroy;
-import org.apache.karaf.shell.inject.Init;
-import org.apache.karaf.shell.inject.Reference;
-import org.apache.karaf.shell.inject.Service;
-
-import static aQute.bnd.osgi.Constants.COMPONENT_ACTIVATE;
-import static aQute.bnd.osgi.Constants.COMPONENT_DEACTIVATE;
-import static aQute.bnd.osgi.Constants.COMPONENT_PROPERTIES;
-import static aQute.bnd.osgi.Constants.COMPONENT_PROVIDE;
-
-/**
- *
- */
-public class InjectAnnotations implements AnalyzerPlugin {
-
-    private Analyzer analyzer;
-
-    @Override
-    public boolean analyzeJar(Analyzer analyzer) throws Exception {
-        try {
-            return doAnalyzeJar(analyzer);
-        } catch (Exception t) {
-            t.printStackTrace(System.out);
-            throw t;
-        }
-    }
-
-    protected boolean doAnalyzeJar(Analyzer analyzer) throws Exception {
-        this.analyzer = analyzer;
-
-        System.out.println("\nLooking for @Service annotated classes\n");
-
-        Collection<Clazz> annotatedComponents = analyzer.getClasses("", Clazz.QUERY.ANNOTATED.toString(), Service.class.getName());
-
-        List<String> components = new ArrayList<String>();
-
-
-        for (Clazz clazz : annotatedComponents) {
-            System.out.println("\nFound @Service annotated class: " + clazz);
-
-            if (clazz.is(Clazz.QUERY.ANNOTATED, new Instruction(Command.class.getName()), analyzer)) {
-                System.out.println("\tCommand");
-                Collector collector = new Collector();
-                clazz.parseClassFileWithCollector(collector);
-
-                Map<String, String> info = new LinkedHashMap<String, String>();
-                info.put(COMPONENT_ACTIVATE, "activate");
-                info.put(COMPONENT_DEACTIVATE, "deactivate");
-                for (String key : collector.references.keySet()) {
-                    info.put(key, collector.references.get(key));
-                }
-                info.put(COMPONENT_PROVIDE, Processor.join(Arrays.asList(new String[] {
-                        Function.class.getName(),
-                        CompletableFunction.class.getName(),
-                        CommandWithAction.class.getName(),
-//                        AbstractCommand.class.getName()
-                })));
-
-                List<String> properties = new ArrayList<String>();
-                properties.add(CommandProcessor.COMMAND_SCOPE + "=" + collector.command.get("scope"));
-                properties.add(CommandProcessor.COMMAND_FUNCTION + "=" + collector.command.get("name"));
-                properties.add("hidden.component=true");
-                info.put(COMPONENT_PROPERTIES, Processor.join(properties));
-
-                TagResource resource = createComponentResource(clazz.getFQN(), ScrCommandSupport.class.getName(), info);
-                analyzer.getJar().putResource("OSGI-INF/" + clazz.getFQN() + ".xml", resource);
-                components.add("OSGI-INF/" + clazz.getFQN() + ".xml");
-                resource.write(System.out);
-                System.out.println();
-
-            } else {
-                System.out.println("\tNot a command");
-                Collector collector = new Collector();
-                clazz.parseClassFileWithCollector(collector);
-
-                Map<String, String> info = new LinkedHashMap<String, String>();
-                if (collector.init != null) {
-                    info.put(COMPONENT_ACTIVATE, collector.init);
-                }
-                if (collector.destroy != null) {
-                    info.put(COMPONENT_DEACTIVATE, collector.destroy);
-                }
-                for (String key : collector.references.keySet()) {
-                    info.put(key, collector.references.get(key));
-                }
-                info.put(COMPONENT_PROVIDE, Processor.join(collector.allClasses));
-                List<String> properties = new ArrayList<String>();
-                properties.add("hidden.component=true");
-                info.put(COMPONENT_PROPERTIES, Processor.join(properties));
-
-                TagResource resource = createComponentResource(clazz.getFQN(), clazz.getFQN(), info);
-                analyzer.getJar().putResource("OSGI-INF/" + clazz.getFQN() + ".xml", resource);
-                components.add("OSGI-INF/" + clazz.getFQN() + ".xml");
-                resource.write(System.out);
-                System.out.println();
-            }
-
-        }
-
-        String name = ScrCommandSupport.class.getName().replace('.', '/') + ".class";
-        analyzer.getJar().putResource(name, new URLResource(ScrCommandSupport.class.getClassLoader().getResource(name)));
-        String pkg = ScrCommandSupport.class.getName();
-        pkg = pkg.substring( 0, pkg.lastIndexOf( '.' ) );
-        Descriptors.PackageRef pkgRef = analyzer.getPackageRef( pkg );
-        if ( !analyzer.getContained().containsKey( pkgRef ) ) {
-            analyzer.getContained().put(pkgRef);
-        }
-        String[] imports = new String[] {
-                "org.apache.felix.gogo.commands",
-                "org.apache.karaf.shell.commands.basic",
-                "org.apache.karaf.shell.console",
-                "org.apache.karaf.shell.inject",
-                "org.osgi.framework",
-                "org.osgi.service.component",
-                "org.slf4j"
-        };
-        for (String importPkg : imports) {
-            pkgRef = analyzer.getPackageRef( importPkg );
-            if ( !analyzer.getReferred().containsKey( pkgRef ) ) {
-                analyzer.getReferred().put( pkgRef );
-            }
-        }
-
-        String prop = analyzer.getProperty(Constants.SERVICE_COMPONENT);
-        for (String comp : components) {
-            if (prop == null || prop.length() == 0) {
-                prop = comp;
-            } else {
-                prop = prop + "," + comp;
-            }
-        }
-        analyzer.setProperty(Constants.SERVICE_COMPONENT, prop);
-
-        return false;
-    }
-
-    TagResource createComponentResource(String name, String impl, Map<String, String> info)
-            throws Exception {
-        Tag tag = new HeaderReader(analyzer).createComponentTag(name, impl, info);
-        return new TagResource(tag);
-    }
-
-    class Collector extends ClassDataCollector {
-        Descriptors.TypeRef zuper;
-        Clazz.MethodDef method;
-        Clazz.FieldDef field;
-
-        String init;
-        String destroy;
-        Annotation command;
-        Map<String, String> references = new LinkedHashMap<String, String>();
-        List<String> allClasses = new ArrayList<String>();
-
-        @Override
-        public void classBegin(int access, Descriptors.TypeRef name) {
-            if (!name.getFQN().equals(Object.class.getName())) {
-                allClasses.add(name.getFQN());
-            }
-        }
-
-        public void implementsInterfaces(Descriptors.TypeRef[] interfaces) throws Exception {
-            if (interfaces != null) {
-                for (Descriptors.TypeRef ref : interfaces) {
-                    allClasses.add(ref.getFQN());
-                }
-            }
-        }
-
-        @Override
-        public void extendsClass(Descriptors.TypeRef zuper) throws Exception {
-            this.zuper = zuper;
-        }
-
-        @Override
-        public void field(Clazz.FieldDef defined) {
-            field = defined;
-        }
-
-        @Override
-        public void method(Clazz.MethodDef defined) {
-            method = defined;
-        }
-
-        @Override
-        public void annotation(Annotation annotation) {
-            String name = annotation.getName().getFQN();
-            if (Command.class.getName().equals(name)) {
-                System.out.println("\tCommand: " + annotation.get("scope") + ":" + annotation.get("name"));
-                command = annotation;
-            }
-            if (Reference.class.getName().equals(name)) {
-                System.out.println("\tReference: field=" + field.getName() + ", type=" + field.getType().getFQN());
-                references.put(field.getName(), field.getType().getFQN());
-            }
-            if (Init.class.getName().equals(name)) {
-                if (init == null) {
-                    System.out.println("\tInit method: " + method.getName());
-                    init = method.getName();
-                }
-            }
-            if (Destroy.class.getName().equals(name)) {
-                if (destroy == null) {
-                    System.out.println("\tDestroy method: " + method.getName());
-                    destroy = method.getName();
-                }
-            }
-        }
-
-        @Override
-        public void classEnd() throws Exception {
-            if (zuper != null) {
-                Clazz clazz = analyzer.findClass(zuper);
-                zuper = null;
-                if (clazz != null) {
-                    clazz.parseClassFileWithCollector(this);
-                }
-            }
-        }
-    }
-
-    static boolean isAnnotated(Clazz.Def def, Class annotation) {
-        Collection<Descriptors.TypeRef> anns = def.getAnnotations();
-        if (anns != null) {
-            for (Descriptors.TypeRef ann : anns) {
-                if (annotation.getName().equals(ann.getFQN())) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/73205de0/scr/support/src/main/java/org/apache/karaf/scr/support/ScrCommandSupport.java
----------------------------------------------------------------------
diff --git a/scr/support/src/main/java/org/apache/karaf/scr/support/ScrCommandSupport.java b/scr/support/src/main/java/org/apache/karaf/scr/support/ScrCommandSupport.java
deleted file mode 100644
index 18eadb0..0000000
--- a/scr/support/src/main/java/org/apache/karaf/scr/support/ScrCommandSupport.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.
- */
-package org.apache.karaf.scr.support;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.felix.gogo.commands.Action;
-import org.apache.karaf.shell.commands.basic.AbstractCommand;
-import org.apache.karaf.shell.console.BundleContextAware;
-import org.apache.karaf.shell.console.CompletableFunction;
-import org.apache.karaf.shell.console.Completer;
-import org.apache.karaf.shell.inject.Init;
-import org.apache.karaf.shell.inject.Reference;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.component.ComponentContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- */
-public class ScrCommandSupport extends AbstractCommand implements CompletableFunction {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(ScrCommandSupport.class);
-
-    private ComponentContext componentContext;
-
-    public ScrCommandSupport() {
-    }
-
-    public void activate(ComponentContext componentContext) {
-        LOGGER.info("Activating SCR command for " + componentContext.getProperties().get("component.name"));
-        this.componentContext = componentContext;
-    }
-
-    public void deactivate(ComponentContext componentContext) {
-    }
-
-    public Class<? extends Action> getActionClass() {
-        try {
-            String className = (String) componentContext.getProperties().get("component.name");
-            return (Class<? extends Action>) componentContext.getBundleContext().getBundle().loadClass(className);
-        } catch (ClassNotFoundException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    @Override
-    public Action createNewAction() {
-        Class actionClass = getActionClass();
-        try {
-            Action action = (Action) actionClass.newInstance();
-            // Inject services
-            for (Class<?> cl = actionClass; cl != Object.class; cl = cl.getSuperclass()) {
-                for (Field field : cl.getDeclaredFields()) {
-                    if (field.getAnnotation(Reference.class) != null) {
-                        Object value;
-                        if (field.getType() == BundleContext.class) {
-                            value = componentContext.getBundleContext();
-                        } else {
-                            value = componentContext.locateService(field.getName());
-                        }
-                        if (value == null) {
-                            throw new RuntimeException("No OSGi service matching " + field.getType().getName());
-                        }
-                        field.setAccessible(true);
-                        field.set(action, value);
-                    }
-                }
-            }
-            if (action instanceof BundleContextAware) {
-                ((BundleContextAware) action).setBundleContext(componentContext.getBundleContext());
-            }
-            for (Method method : actionClass.getDeclaredMethods()) {
-                Init ann = method.getAnnotation(Init.class);
-                if (ann != null && method.getParameterTypes().length == 0 && method.getReturnType() == void.class) {
-                    method.setAccessible(true);
-                    method.invoke(action);
-                }
-            }
-            return action;
-        } catch (Exception e) {
-            throw new RuntimeException("Unable to creation command action " + actionClass.getName(), e);
-        }
-    }
-
-    @Override
-    public List<Completer> getCompleters() {
-        return null;
-    }
-
-    @Override
-    public Map<String, Completer> getOptionalCompleters() {
-        return null;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/73205de0/tooling/karaf-scr-maven-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-scr-maven-plugin/pom.xml b/tooling/karaf-scr-maven-plugin/pom.xml
new file mode 100644
index 0000000..1f12340
--- /dev/null
+++ b/tooling/karaf-scr-maven-plugin/pom.xml
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.karaf.tooling</groupId>
+        <artifactId>tooling</artifactId>
+        <version>3.0.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>karaf-scr-maven-plugin</artifactId>
+    <packaging>maven-plugin</packaging>
+    <name>Apache Karaf :: Tooling :: Maven Karaf SCR Plugin</name>
+
+    <properties>
+        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-plugin-api</artifactId>
+            <version>3.0.3</version>
+        </dependency>
+        <dependency>
+           <groupId>org.sonatype.aether</groupId>
+           <artifactId>aether-api</artifactId>
+           <version>1.11</version>
+         </dependency>
+         <dependency>
+           <groupId>org.sonatype.aether</groupId>
+           <artifactId>aether-util</artifactId>
+           <version>1.11</version>
+         </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-artifact</artifactId>
+            <version>3.0.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-core</artifactId>
+            <version>3.0.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-compat</artifactId>
+            <version>3.0.3</version>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-jdk14</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.maven.shared</groupId>
+            <artifactId>maven-filtering</artifactId>
+            <version>1.0-beta-4</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-utils</artifactId>
+            <version>3.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>maven-bundle-plugin</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>org.apache.felix.bundlerepository</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.fileinstall</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.features</groupId>
+            <artifactId>org.apache.karaf.features.core</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>org.apache.karaf.shell.console</artifactId>
+                    <groupId>org.apache.karaf.shell</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.url</groupId>
+            <artifactId>pax-url-wrap</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.url</groupId>
+            <artifactId>pax-url-aether</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.deployer</groupId>
+            <artifactId>org.apache.karaf.deployer.spring</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.deployer</groupId>
+            <artifactId>org.apache.karaf.deployer.blueprint</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.deployer</groupId>
+            <artifactId>org.apache.karaf.deployer.features</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.deployer</groupId>
+            <artifactId>org.apache.karaf.deployer.kar</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.kar</groupId>
+            <artifactId>org.apache.karaf.kar.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.ant</artifactId>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.karaf.shell</groupId>
+          <artifactId>org.apache.karaf.shell.console</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.gogo.runtime</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.xbean</groupId>
+          <artifactId>xbean-finder-shaded</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.generator</artifactId>
+            <version>1.5.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.ds-annotations</artifactId>
+            <version>1.2.4</version>
+        </dependency>
+        <dependency>
+            <groupId>org.sonatype.plexus</groupId>
+            <artifactId>plexus-build-api</artifactId>
+            <version>0.0.7</version>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>ci-build-profile</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-invoker-plugin</artifactId>
+                        <version>1.6</version>
+                        <configuration>
+                            <debug>true</debug>
+                            <projectsDirectory>src/it</projectsDirectory>
+                            <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+                            <pomIncludes>
+                                <pomInclude>*/pom.xml</pomInclude>
+                            </pomIncludes>
+                            <postBuildHookScript>verify</postBuildHookScript>
+                            <localRepositoryPath>${project.build.directory}/system</localRepositoryPath>
+                            <!--<settingsFile>src/it/settings.xml</settingsFile>-->
+                            <mavenOpts>-Djava.io.tmpdir=${project.build.directory}</mavenOpts>
+                            <goals>
+                                <goal>install</goal>
+                            </goals>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>integration-test</id>
+                                <goals>
+                                    <goal>install</goal>
+                                    <goal>run</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                        <dependencies>
+                            <dependency>
+                                <groupId>xmlunit</groupId>
+                                <artifactId>xmlunit</artifactId>
+                                <version>1.3</version>
+                            </dependency>
+                        </dependencies>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+    <reporting>
+        <!--<outputDirectory>target/site</outputDirectory>-->
+        <plugins>
+            <plugin>
+                <artifactId>maven-plugin-plugin</artifactId>
+                <version>2.9</version>
+            </plugin>
+        </plugins>
+    </reporting>
+
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/73205de0/tooling/karaf-scr-maven-plugin/src/main/java/org/apache/karaf/tooling/scr/ScrCommandMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-scr-maven-plugin/src/main/java/org/apache/karaf/tooling/scr/ScrCommandMojo.java b/tooling/karaf-scr-maven-plugin/src/main/java/org/apache/karaf/tooling/scr/ScrCommandMojo.java
new file mode 100644
index 0000000..377dd60
--- /dev/null
+++ b/tooling/karaf-scr-maven-plugin/src/main/java/org/apache/karaf/tooling/scr/ScrCommandMojo.java
@@ -0,0 +1,309 @@
+package org.apache.karaf.tooling.scr;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.apache.felix.service.command.CommandProcessor;
+import org.apache.felix.service.command.Function;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.CommandWithAction;
+import org.apache.karaf.shell.console.CompletableFunction;
+import org.apache.karaf.shell.inject.Reference;
+import org.apache.karaf.shell.inject.Service;
+import org.apache.maven.artifact.DependencyResolutionRequiredException;
+import org.apache.maven.model.Resource;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.apache.xbean.finder.ClassFinder;
+
+/**
+ * The <code>ScrCommandMojo</code> generates a service descriptor file based
+ * on annotations found in the sources.
+ *
+ * @goal scr
+ * @phase process-classes
+ * @threadSafe
+ * @description Build Service Descriptors from Java Source
+ * @requiresDependencyResolution compile
+ */
+public class ScrCommandMojo extends AbstractMojo {
+
+    /**
+     * The Maven project.
+     *
+     * @parameter expression="project"
+     * @required
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * @parameter expression="${project.build.directory}/generated-scr-commands"
+     */
+    private File outputDirectory;
+
+    /**
+     * @parameter
+     */
+    private int ranking;
+
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        try {
+            ClassFinder finder = new ClassFinder(getClassLoader());
+            List<String> components = new ArrayList<String>();
+            boolean hasCommand = false;
+            for (Class<?> clazz : finder.findAnnotatedClasses(Service.class)) {
+
+                Command cmd = clazz.getAnnotation(Command.class);
+                if (cmd != null) {
+                    System.out.println("\nFound command: " + clazz.getName() + "\n\t" + cmd.scope() + ":" + cmd.name() + "\n");
+
+                    StringBuilder sb = new StringBuilder();
+                    sb.append("<?xml version='1.1'?>\n");
+                    sb.append("<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"")
+                            .append(clazz.getName())
+                            .append("\" activate=\"activate\" deactivate=\"deactivate\">\n");
+                    sb.append("  <implementation class=\"").append(ScrCommandSupport.class.getName()).append("\"/>\n");
+                    sb.append("  <service>\n");
+                    sb.append("    <provide interface=\"").append(Function.class.getName()).append("\"/>\n");
+                    sb.append("    <provide interface=\"").append(CompletableFunction.class.getName()).append("\"/>\n");
+                    sb.append("    <provide interface=\"").append(CommandWithAction.class.getName()).append("\"/>\n");
+                    sb.append("  </service>\n");
+                    Map<String, Class> refs = getReferences(clazz);
+                    for (String key : refs.keySet()) {
+                        sb.append("  <reference name=\"").append(key).append("\" cardinality=\"1..1\" interface=\"")
+                                .append(refs.get(key).getName()).append("\"/>\n");
+                    }
+                    sb.append("  <property name=\"hidden.component\" value=\"true\"/>\n");
+                    if (ranking != 0) {
+                        sb.append("  <property name=\"service.ranking\" value=\"").append(ranking).append("\"/>\n");
+                    }
+                    sb.append("  <property name=\"").append(CommandProcessor.COMMAND_SCOPE).append("\" value=\"").append(cmd.scope()).append("\"/>\n");
+                    sb.append("  <property name=\"").append(CommandProcessor.COMMAND_FUNCTION).append("\" value=\"").append(cmd.name()).append("\"/>\n");
+                    sb.append("</scr:component>\n");
+                    String component = "OSGI-INF/" + clazz.getName() + ".xml";
+                    components.add(component);
+                    File file = new File(outputDirectory, component);
+                    file.getParentFile().mkdirs();
+                    Writer w = new FileWriter(file);
+                    w.write(sb.toString());
+                    w.close();
+                    hasCommand = true;
+                } else {
+                    System.out.println("\nFound service: " + clazz.getName() + "\n");
+
+                    StringBuilder sb = new StringBuilder();
+                    sb.append("<?xml version='1.1'?>\n");
+                    sb.append("<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"")
+                            .append(clazz.getName())
+                            .append("\" activate=\"activate\" deactivate=\"deactivate\">\n");
+                    sb.append("  <implementation class=\"").append(clazz.getName()).append("\"/>\n");
+                    sb.append("  <service>\n");
+                    List<Class> allClasses = new ArrayList<Class>();
+                    addAllClasses(allClasses, clazz);
+                    for (Class cl : allClasses) {
+                        sb.append("    <provide interface=\"").append(cl.getName()).append("\"/>\n");
+                    }
+                    sb.append("  </service>\n");
+                    Map<String, Class> refs = getReferences(clazz);
+                    for (String key : refs.keySet()) {
+                        sb.append("  <reference name=\"").append(key).append("\" cardinality=\"1..1\" interface=\"")
+                                .append(refs.get(key).getName()).append("\"");
+                        String[] bind = getBindMethods(clazz, key, refs.get(key));
+                        if (bind[0] != null) {
+                            sb.append(" bind=\"").append(bind[0]).append("\"");
+                        }
+                        if (bind[1] != null) {
+                            sb.append(" unbind=\"").append(bind[1]).append("\"");
+                        }
+                        sb.append("/>\n");
+                    }
+                    sb.append("  <property name=\"hidden.component\" value=\"true\"/>\n");
+                    if (ranking != 0) {
+                        sb.append("  <property name=\"service.ranking\" value=\"").append(ranking).append("\"/>\n");
+                    }
+                    sb.append("</scr:component>\n");
+                    String component = "OSGI-INF/" + clazz.getName() + ".xml";
+                    components.add(component);
+                    File file = new File(outputDirectory, component);
+                    file.getParentFile().mkdirs();
+                    Writer w = new FileWriter(file);
+                    w.write(sb.toString());
+                    w.close();
+                }
+            }
+            if (!components.isEmpty()) {
+                if (hasCommand) {
+                    String name = ScrCommandSupport.class.getName().replace('.', '/') + ".class";
+                    File file = new File(outputDirectory, name);
+                    file.getParentFile().mkdirs();
+                    URL url = getClass().getClassLoader().getResource(name);
+                    InputStream is = url.openStream();
+                    FileOutputStream fos = new FileOutputStream(file);
+                    copy(is, fos);
+                    is.close();
+                    fos.close();
+                    name = ScrCommandSupport.class.getName();
+                    name = name.substring(0, name.lastIndexOf('.'));
+                    setPrivatePackageHeader(name);
+                }
+                setServiceComponentHeader(components);
+                updateProjectResources();
+            }
+        } catch (Exception e) {
+            throw new MojoExecutionException("Error executing SCR command scanner", e);
+        }
+    }
+
+    private String[] getBindMethods(Class<?> clazz, String key, Class type) {
+        String cap = key.substring(0, 1).toUpperCase() + key.substring(1);
+        Method bind = null;
+        Method unbind = null;
+        try {
+            bind = clazz.getMethod("set" + cap, type);
+        } catch (NoSuchMethodException e0) {
+            try {
+                bind = clazz.getMethod("bind" + cap, type);
+            } catch (NoSuchMethodException e1) {
+            }
+        }
+        if (bind != null) {
+            try {
+                unbind = clazz.getMethod("un" + bind.getName(), type);
+            } catch (NoSuchMethodException e0) {
+            }
+        }
+        return new String[] {
+                bind != null ? bind.getName() : null,
+                unbind != null ? unbind.getName() : null
+        };
+    }
+
+    private void addAllClasses(List<Class> allClasses, Class<?> clazz) {
+        if (clazz != null && clazz != Object.class) {
+            if (allClasses.add(clazz)) {
+                addAllClasses(allClasses, clazz.getSuperclass());
+                for (Class cl : clazz.getInterfaces()) {
+                    addAllClasses(allClasses, cl);
+                }
+            }
+        }
+    }
+
+    private Map<String, Class> getReferences(Class<?> clazz) {
+        Map<String, Class> refs = new HashMap<String, Class>();
+        while (clazz != null) {
+            for (Field field : clazz.getDeclaredFields()) {
+                if (field.getAnnotation(Reference.class) != null) {
+                    refs.put(field.getName(), field.getType());
+                }
+            }
+            clazz = clazz.getSuperclass();
+        }
+        return refs;
+    }
+
+    private ClassLoader getClassLoader() throws MojoFailureException, DependencyResolutionRequiredException, MalformedURLException {
+        List<URL> urls = new ArrayList<URL>();
+        for (Object object : project.getCompileClasspathElements()) {
+            String path = (String) object;
+            urls.add(new File(path).toURL());
+        }
+        ClassLoader classLoader = new URLClassLoader(urls.toArray(new URL[] {}), getClass().getClassLoader());
+        return classLoader;
+    }
+
+    private void setPrivatePackageHeader(String pkg) {
+        String header = project.getProperties().getProperty("Private-Package");
+        if (header != null && header.length() > 0) {
+            header += "," + pkg;
+        } else {
+            header = pkg;
+        }
+        project.getProperties().setProperty("Private-Package", header);
+        System.out.println("\nPrivate-Package: " + header + "\n");
+    }
+
+    /**
+     * Set the service component header based on the scr files.
+     */
+    private void setServiceComponentHeader(final List<String> files) {
+        if ( files != null && files.size() > 0 ) {
+            final String svcHeader = project.getProperties().getProperty("Service-Component");
+            final Set<String> xmlFiles = new HashSet<String>();
+            if ( svcHeader != null ) {
+                final StringTokenizer st = new StringTokenizer(svcHeader, ",");
+                while ( st.hasMoreTokens() ) {
+                    final String token = st.nextToken();
+                    xmlFiles.add(token.trim());
+                }
+            }
+
+            for(final String path : files) {
+                xmlFiles.add(path);
+            }
+            final StringBuilder sb = new StringBuilder();
+            boolean first = true;
+            for(final String entry : xmlFiles) {
+                if ( !first ) {
+                    sb.append(", ");
+                } else {
+                    first = false;
+                }
+                sb.append(entry);
+            }
+            project.getProperties().setProperty("Service-Component", sb.toString());
+            System.out.println("\nService-Component: " + sb.toString() + "\n");
+        }
+    }
+
+    /**
+     * Update the Maven project resources.
+     */
+    private void updateProjectResources() {
+        // now add the descriptor directory to the maven resources
+        final String ourRsrcPath = this.outputDirectory.getAbsolutePath();
+        boolean found = false;
+        @SuppressWarnings("unchecked")
+        final Iterator<Resource> rsrcIterator = this.project.getResources().iterator();
+        while (!found && rsrcIterator.hasNext()) {
+            final Resource rsrc = rsrcIterator.next();
+            found = rsrc.getDirectory().equals(ourRsrcPath);
+        }
+        if (!found) {
+            final Resource resource = new Resource();
+            resource.setDirectory(this.outputDirectory.getAbsolutePath());
+            this.project.addResource(resource);
+        }
+    }
+
+    static void copy(InputStream is, OutputStream os) throws IOException {
+        byte[] buffer = new byte[8192];
+        int l;
+        while ((l = is.read(buffer)) > 0) {
+            os.write(buffer, 0, l);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/73205de0/tooling/karaf-scr-maven-plugin/src/main/java/org/apache/karaf/tooling/scr/ScrCommandSupport.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-scr-maven-plugin/src/main/java/org/apache/karaf/tooling/scr/ScrCommandSupport.java b/tooling/karaf-scr-maven-plugin/src/main/java/org/apache/karaf/tooling/scr/ScrCommandSupport.java
new file mode 100644
index 0000000..c6c52ef
--- /dev/null
+++ b/tooling/karaf-scr-maven-plugin/src/main/java/org/apache/karaf/tooling/scr/ScrCommandSupport.java
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+package org.apache.karaf.tooling.scr;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.gogo.commands.Action;
+import org.apache.karaf.shell.commands.basic.AbstractCommand;
+import org.apache.karaf.shell.console.BundleContextAware;
+import org.apache.karaf.shell.console.CompletableFunction;
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.inject.Init;
+import org.apache.karaf.shell.inject.Reference;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ */
+public class ScrCommandSupport extends AbstractCommand implements CompletableFunction {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ScrCommandSupport.class);
+
+    private ComponentContext componentContext;
+
+    public ScrCommandSupport() {
+    }
+
+    public void activate(ComponentContext componentContext) {
+        LOGGER.info("Activating SCR command for " + componentContext.getProperties().get("component.name"));
+        this.componentContext = componentContext;
+    }
+
+    public void deactivate(ComponentContext componentContext) {
+    }
+
+    public Class<? extends Action> getActionClass() {
+        try {
+            String className = (String) componentContext.getProperties().get("component.name");
+            return (Class<? extends Action>) componentContext.getBundleContext().getBundle().loadClass(className);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Override
+    public Action createNewAction() {
+        Class actionClass = getActionClass();
+        try {
+            Action action = (Action) actionClass.newInstance();
+            // Inject services
+            for (Class<?> cl = actionClass; cl != Object.class; cl = cl.getSuperclass()) {
+                for (Field field : cl.getDeclaredFields()) {
+                    if (field.getAnnotation(Reference.class) != null) {
+                        Object value;
+                        if (field.getType() == BundleContext.class) {
+                            value = componentContext.getBundleContext();
+                        } else {
+                            value = componentContext.locateService(field.getName());
+                        }
+                        if (value == null) {
+                            throw new RuntimeException("No OSGi service matching " + field.getType().getName());
+                        }
+                        field.setAccessible(true);
+                        field.set(action, value);
+                    }
+                }
+            }
+            if (action instanceof BundleContextAware) {
+                ((BundleContextAware) action).setBundleContext(componentContext.getBundleContext());
+            }
+            for (Method method : actionClass.getDeclaredMethods()) {
+                Init ann = method.getAnnotation(Init.class);
+                if (ann != null && method.getParameterTypes().length == 0 && method.getReturnType() == void.class) {
+                    method.setAccessible(true);
+                    method.invoke(action);
+                }
+            }
+            return action;
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to creation command action " + actionClass.getName(), e);
+        }
+    }
+
+    @Override
+    public List<Completer> getCompleters() {
+        return null;
+    }
+
+    @Override
+    public Map<String, Completer> getOptionalCompleters() {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/73205de0/tooling/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/pom.xml b/tooling/pom.xml
index d3ee158..9abc2cd 100644
--- a/tooling/pom.xml
+++ b/tooling/pom.xml
@@ -34,6 +34,7 @@
     <name>Apache Karaf :: Tooling</name>
 
     <modules>
+        <module>karaf-scr-maven-plugin</module>
         <module>karaf-maven-plugin</module>
     </modules>