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 <[email protected]> Authored: Wed Feb 19 16:00:59 2014 +0100 Committer: Guillaume Nodet <[email protected]> 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>
