Initial version of the bnd-ipojo-plugin (FELIX-3080).
Thanks again to Guillaume Sauthier.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1159175 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/bnd-ipojo-plugin/pom.xml b/ipojo/bnd-ipojo-plugin/pom.xml
new file mode 100644
index 0000000..ed842f6
--- /dev/null
+++ b/ipojo/bnd-ipojo-plugin/pom.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>1.2.1</version>
+ <relativePath>../../pom/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>bnd-ipojo-plugin</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <name>Apache Felix iPOJO Bnd Plugin</name>
+
+ <developers>
+ <developer>
+ <name>Guillaume Sauthier</name>
+ <organization>OW2 Consortium</organization>
+ <roles>
+ <role>developer</role>
+ </roles>
+ </developer>
+ </developers>
+
+ <dependencies>
+ <dependency>
+ <groupId>biz.aQute</groupId>
+ <artifactId>bndlib</artifactId>
+ <version>1.43.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/BndJarResourceStore.java b/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/BndJarResourceStore.java
new file mode 100644
index 0000000..7d666f2
--- /dev/null
+++ b/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/BndJarResourceStore.java
@@ -0,0 +1,148 @@
+/*
+ * 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.felix.ipojo.bnd;
+
+import aQute.lib.osgi.Analyzer;
+import aQute.lib.osgi.Clazz;
+import aQute.lib.osgi.Jar;
+import aQute.lib.osgi.Resource;
+import aQute.libg.reporter.Reporter;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Handler;
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.render.MetadataRenderer;
+import org.apache.felix.ipojo.manipulator.util.Metadatas;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: guillaume
+ * Date: 11/08/11
+ * Time: 22:40
+ * To change this template use File | Settings | File Templates.
+ */
+public class BndJarResourceStore implements ResourceStore {
+
+ private Analyzer analyzer;
+ private Reporter reporter;
+
+ private MetadataRenderer renderer = new MetadataRenderer();
+
+ public BndJarResourceStore(Analyzer analyzer, Reporter reporter) {
+ this.analyzer = analyzer;
+ this.reporter = reporter;
+ }
+
+ public byte[] read(String path) throws IOException {
+ Resource resource = analyzer.getJar().getResource(path);
+ InputStream is = null;
+ try {
+ is = resource.openInputStream();
+ } catch (Exception e) {
+ throw new IOException("Cannot read " + path);
+ }
+ return Streams.readBytes(is);
+ }
+
+ public void accept(ResourceVisitor visitor) {
+
+ try {
+ // Only visit classes annotated with @Component or @Handler
+ String annotations = Component.class.getName() + "|" + Handler.class.getName();
+
+ Collection<Clazz> classes = analyzer.getClasses("",
+ Clazz.QUERY.ANNOTATION.name(), annotations,
+ Clazz.QUERY.NAMED.name(), "*");
+
+ // Iterates over discovered resources
+ for (Clazz clazz : classes) {
+ visitor.visit(clazz.getPath());
+ }
+ } catch (Exception e) {
+ reporter.error("Cannot find iPOJO annotated types: " + e.getMessage());
+ }
+ }
+
+ public void open() throws IOException {
+ // nothing to do
+ }
+
+ public void writeMetadata(Element metadata) {
+
+ // Find referred packages and add them into Bnd
+ for (String referred : Metadatas.findReferredPackages(metadata)) {
+ if (analyzer.getReferred().get(referred) == null) {
+ // The given package is not referred ATM
+ analyzer.getReferred().put(referred, new HashMap<String, String>());
+ }
+ }
+
+ // Write the iPOJO header
+ String components = analyzer.getProperty("IPOJO-Components");
+ StringBuilder builder = new StringBuilder();
+
+ if (components != null) {
+ builder.append(components);
+ }
+ builder.append(renderer.render(metadata));
+
+ if (builder.length() != 0) {
+ analyzer.setProperty("IPOJO-Components", builder.toString());
+ }
+
+
+ }
+
+ public void write(String resourcePath, byte[] resource) throws IOException {
+ Jar jar = analyzer.getJar();
+ jar.putResource(resourcePath, new ByteArrayResource(resource));
+ }
+
+ public void close() throws IOException {
+
+ // Add some mandatory imported packages
+ Map<String, String> version = new TreeMap<String, String>();
+ version.put("version", Pojoization.IPOJO_PACKAGE_VERSION);
+
+ if (analyzer.getReferred().get("org.apache.felix.ipojo") == null) {
+ analyzer.getReferred().put("org.apache.felix.ipojo", version);
+ }
+ if (analyzer.getReferred().get("org.apache.felix.ipojo.architecture") == null) {
+ analyzer.getReferred().put("org.apache.felix.ipojo.architecture", version);
+ }
+ if (analyzer.getReferred().get("org.osgi.service.cm") == null) {
+ Map<String, String> cm = new TreeMap<String, String>();
+ cm.put("version", "1.2");
+ analyzer.getReferred().put("org.osgi.service.cm", cm);
+ }
+ if (analyzer.getReferred().get("org.osgi.service.log") == null) {
+ Map<String, String> log = new TreeMap<String, String>();
+ log.put("version", "1.3");
+ analyzer.getReferred().put("org.osgi.service.log", log);
+ }
+
+ }
+}
diff --git a/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/BndReporter.java b/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/BndReporter.java
new file mode 100644
index 0000000..9e56151
--- /dev/null
+++ b/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/BndReporter.java
@@ -0,0 +1,83 @@
+/*
+ * 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.felix.ipojo.bnd;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import aQute.libg.reporter.Reporter;
+import org.apache.felix.ipojo.manipulator.reporter.EmptyReporter;
+
+/**
+ * A {@code BndReporter} knows how to wrap a Bnd Reporter into an iPOJO Reporter.
+ *
+ * @author Guillaume Sauthier
+ */
+public class BndReporter extends EmptyReporter {
+
+ /**
+ * Bnd reporter.
+ */
+ private Reporter reporter;
+
+ /**
+ * Errors which occur during the manipulation.
+ */
+ private List<String> m_errors = new ArrayList<String>();
+
+ /**
+ * Warnings which occur during the manipulation.
+ */
+ private List<String> m_warnings = new ArrayList<String>();
+
+ public BndReporter(aQute.libg.reporter.Reporter reporter) {
+ this.reporter = reporter;
+ }
+
+ public List<String> getErrors() {
+ return m_errors;
+ }
+
+ public List<String> getWarnings() {
+ return m_warnings;
+ }
+
+ @Override
+ public void trace(String message, Object... args) {
+ reporter.trace(message, args);
+ }
+
+ @Override
+ public void info(String message, Object... args) {
+ reporter.progress(message, args);
+ }
+
+ @Override
+ public void warn(String message, Object... args) {
+ reporter.warning(message, args);
+ m_warnings.add(String.format(message, args));
+ }
+
+ @Override
+ public void error(String message, Object... args) {
+ reporter.error(message, args);
+ m_errors.add(String.format(message, args));
+ }
+}
diff --git a/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/ByteArrayResource.java b/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/ByteArrayResource.java
new file mode 100644
index 0000000..260d4ac
--- /dev/null
+++ b/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/ByteArrayResource.java
@@ -0,0 +1,41 @@
+/*
+ * 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.felix.ipojo.bnd;
+
+import aQute.lib.osgi.AbstractResource;
+
+/**
+ * A {@code ByteArrayResource} is ...
+ *
+ * @author Guillaume Sauthier
+ */
+public class ByteArrayResource extends AbstractResource {
+
+ private byte[] content;
+
+ public ByteArrayResource(byte[] content) {
+ super(System.currentTimeMillis());
+ this.content = content;
+ }
+
+ @Override
+ protected byte[] getBytes() throws Exception {
+ return content;
+ }
+}
diff --git a/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/PojoizationPlugin.java b/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/PojoizationPlugin.java
new file mode 100644
index 0000000..15f66f0
--- /dev/null
+++ b/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/PojoizationPlugin.java
@@ -0,0 +1,151 @@
+/*
+ * 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.felix.ipojo.bnd;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import aQute.bnd.service.AnalyzerPlugin;
+import aQute.bnd.service.Plugin;
+import aQute.lib.osgi.Analyzer;
+import aQute.lib.osgi.Resource;
+import aQute.libg.reporter.Reporter;
+import org.apache.felix.ipojo.manipulator.ManipulationVisitor;
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.metadata.AnnotationMetadataProvider;
+import org.apache.felix.ipojo.manipulator.metadata.CacheableMetadataProvider;
+import org.apache.felix.ipojo.manipulator.metadata.CompositeMetadataProvider;
+import org.apache.felix.ipojo.manipulator.metadata.FileMetadataProvider;
+import org.apache.felix.ipojo.manipulator.visitor.check.CheckFieldConsistencyVisitor;
+import org.apache.felix.ipojo.manipulator.visitor.writer.ManipulatedResourcesWriter;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code BndIpojoPlugin} is ...
+ *
+ * @author Guillaume Sauthier
+ */
+public class PojoizationPlugin implements Plugin, AnalyzerPlugin {
+
+ private static final String PROPERTY_METADATA = "metadata";
+ private static final String PROPERTY_USE_LOCAL_SCHEMAS = "use-local-schemas";
+
+ private static final String DEFAULT_METADATA = "META-INF/metadata.xml";
+ private static final boolean DEFAULT_USE_LOCAL_SCHEMAS = false;
+
+ private String metadata = DEFAULT_METADATA;
+ private boolean useLocalSchemas = DEFAULT_USE_LOCAL_SCHEMAS;
+
+ private Reporter reporter;
+
+ public void setProperties(Map<String, String> configuration) {
+
+ // Use metadata file if any
+ if (configuration.containsKey(PROPERTY_METADATA)) {
+ metadata = configuration.get(PROPERTY_METADATA);
+ }
+
+ // Use local schemas ?
+ if (configuration.containsKey(PROPERTY_USE_LOCAL_SCHEMAS)) {
+ useLocalSchemas = true;
+ }
+ }
+
+ public void setReporter(Reporter reporter) {
+ this.reporter = reporter;
+ }
+
+ public boolean analyzeJar(Analyzer analyzer) throws Exception {
+
+ long start = System.currentTimeMillis();
+
+ // Wraps the Bnd Reporter
+ BndReporter reporter = new BndReporter(this.reporter);
+
+ // Build ResourceStore
+ BndJarResourceStore store = new BndJarResourceStore(analyzer, this.reporter);
+
+ // Build MetadataProvider
+ CompositeMetadataProvider provider = new CompositeMetadataProvider(reporter);
+
+ File file = new File(metadata);
+ if (file.exists()) {
+ // Absolute file system resource
+ FileMetadataProvider fmp = new FileMetadataProvider(file, reporter);
+ fmp.setValidateUsingLocalSchemas(useLocalSchemas);
+ provider.addMetadataProvider(fmp);
+ } else {
+ // In archive resource
+ Resource resource = analyzer.getJar().getResource(metadata);
+ if (resource != null) {
+ ResourceMetadataProvider rmp = new ResourceMetadataProvider(resource, reporter);
+ rmp.setValidateUsingLocalSchemas(useLocalSchemas);
+ provider.addMetadataProvider(rmp);
+ }
+ }
+ provider.addMetadataProvider(new AnnotationMetadataProvider(store, reporter));
+
+ CacheableMetadataProvider cache = new CacheableMetadataProvider(provider);
+ if (cache.getMetadatas().isEmpty()) {
+ return false;
+ }
+
+ Pojoization pojoization = new Pojoization(reporter);
+ if (useLocalSchemas) {
+ pojoization.setUseLocalXSD();
+ }
+
+ pojoization.pojoization(store, cache, createVisitor(store, reporter));
+
+ int nbComponents = findElements(cache.getMetadatas(), "component").size();
+ int nbHandlers = findElements(cache.getMetadatas(), "handler").size();
+ this.reporter.progress("iPOJO manipulation performed performed in %s ms (%d components, %d handlers).",
+ (System.currentTimeMillis() - start),
+ nbComponents,
+ nbHandlers);
+
+ // Return true if a new run should be performed after the analyze
+ return false;
+ }
+
+ private List<Element> findElements(List<Element> metadatas, String name) {
+ List<Element> found = new ArrayList<Element>();
+ for (Element element : metadatas) {
+ if (name.equalsIgnoreCase(element.getName())) {
+ found.add(element);
+ }
+ }
+ return found;
+ }
+
+ private ManipulationVisitor createVisitor(ResourceStore store, BndReporter reporter) {
+ ManipulatedResourcesWriter writer = new ManipulatedResourcesWriter();
+ writer.setReporter(reporter);
+ writer.setResourceStore(store);
+
+ CheckFieldConsistencyVisitor checkFieldConsistencyVisitor = new CheckFieldConsistencyVisitor(writer);
+ checkFieldConsistencyVisitor.setReporter(reporter);
+ return checkFieldConsistencyVisitor;
+
+ }
+
+}
diff --git a/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/ResourceMetadataProvider.java b/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/ResourceMetadataProvider.java
new file mode 100644
index 0000000..15f4772
--- /dev/null
+++ b/ipojo/bnd-ipojo-plugin/src/main/java/org/apache/felix/ipojo/bnd/ResourceMetadataProvider.java
@@ -0,0 +1,73 @@
+/*
+ * 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.felix.ipojo.bnd;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import aQute.lib.osgi.Resource;
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.StreamMetadataProvider;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code ResourceMetadataProvider} is ...
+ *
+ * @author Guillaume Sauthier
+ */
+public class ResourceMetadataProvider implements MetadataProvider {
+
+ private Resource resource;
+
+ private List<Element> cached;
+
+ private boolean validateUsingLocalSchemas = false;
+
+ private Reporter reporter;
+
+ public ResourceMetadataProvider(Resource resource, Reporter reporter) {
+ this.resource = resource;
+ this.reporter = reporter;
+ }
+
+ public void setValidateUsingLocalSchemas(boolean validateUsingLocalSchemas) {
+ this.validateUsingLocalSchemas = validateUsingLocalSchemas;
+ }
+
+ public List<Element> getMetadatas() throws IOException {
+ if (cached == null) {
+ cached = new ArrayList<Element>();
+ InputStream stream = null;
+ try {
+ stream = resource.openInputStream();
+ } catch (Exception e) {
+ reporter.error(e.getMessage());
+ throw new IOException("Cannot read metadata");
+ }
+ StreamMetadataProvider provider = new StreamMetadataProvider(stream, reporter);
+ provider.setValidateUsingLocalSchemas(validateUsingLocalSchemas);
+ cached.addAll(provider.getMetadatas());
+ }
+
+ return cached;
+ }
+}