blob: f555b21ee73afd2be210ce116f16a542b3961fe5 [file] [log] [blame]
/*
* 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 static java.lang.String.format;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
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.Constants;
import org.apache.felix.ipojo.manipulator.util.Metadatas;
import org.apache.felix.ipojo.manipulator.util.Streams;
import org.apache.felix.ipojo.metadata.Element;
import aQute.bnd.header.Attrs;
import aQute.bnd.osgi.Analyzer;
import aQute.bnd.osgi.Clazz;
import aQute.bnd.osgi.Jar;
import aQute.bnd.osgi.Resource;
import aQute.service.reporter.Reporter;
public class BndJarResourceStore implements ResourceStore {
private Analyzer m_analyzer;
private Reporter m_reporter;
private MetadataRenderer m_renderer = new MetadataRenderer();
private List<Element> m_metadata;
private boolean m_includeEmbedComponents;
public BndJarResourceStore(Analyzer analyzer, Reporter reporter) {
m_metadata = new ArrayList<Element>();
m_analyzer = analyzer;
m_reporter = reporter;
}
public byte[] read(String path) throws IOException {
// Find the resource either in the global jar or in one of the embed dependencies
Resource resource = m_analyzer.getJar().getResource(path);
if (resource == null) {
Jar embed = findJar(path);
if (embed == null) {
throw new IOException(format("Cannot find resource %s in jar and classpath", path));
}
resource = embed.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 {
// Collect all annotated classes
Collection<Clazz> classes = m_analyzer.getClasses("",
Clazz.QUERY.CLASSANNOTATIONS.name());
classes = filter(classes);
// Iterates over discovered resources
for (Clazz clazz : classes) {
visitor.visit(clazz.getAbsolutePath());
}
} catch (Exception e) {
m_reporter.error("Cannot find iPOJO annotated types: " + e.getMessage());
}
}
private Collection<Clazz> filter(Collection<Clazz> classes) throws Exception {
Set<Clazz> manipulable = new HashSet<Clazz>();
for (Clazz clazz : classes) {
// If it is in the main jar, simply use it
if (m_analyzer.getJar().getResource(clazz.getAbsolutePath()) != null) {
manipulable.add(clazz);
continue;
}
if (m_includeEmbedComponents) {
// Otherwise ...
// Try to see if it is in an embed dependencies
Jar jar = findJar(clazz.getAbsolutePath());
if (jar == null) {
m_reporter.error("Resource for class %s not found in classpath", clazz.getFQN());
continue;
}
// Is it a Bundle ?
if (jar.getBsn() != null) {
// OSGi Bundle case
// Check if the bundle was manipulated before
Attributes attr = jar.getManifest().getMainAttributes();
if (Manifests.getComponents(attr) != null) {
// Bundle has been previously manipulated
// TODO We should ignore the resource since it was already manipulated
// TODO But we should also merge its IPOJO-Components header
} else {
// Bundle was not manipulated
manipulable.add(clazz);
}
} else {
// Simple Jar file with iPOJO annotations
m_reporter.warning("Class %s found in a non-Bundle archive %s", clazz.getFQN(), jar.getName());
continue;
}
} else {
m_reporter.warning("Embed components are excluded, Component %s will not be manipulated", clazz.getFQN());
}
}
return manipulable;
}
private Jar findJar(String path) {
for (Jar jar : m_analyzer.getClasspath()) {
if (jar.getResource(path) != null) {
return jar;
}
}
return null;
}
public void open() throws IOException {
// nothing to do
}
public void writeMetadata(Element metadata) {
m_metadata.add(metadata);
// Find referred packages and add them into Bnd
for (String referred : Metadatas.findReferredPackages(metadata)) {
if (!m_analyzer.getReferred().containsFQN(referred)) {
// The given package is not referred ATM
m_analyzer.getReferred().put(m_analyzer.getPackageRef(referred),
new Attrs());
}
}
// IPOJO-Components will be written during the close method.
}
public void write(String resourcePath, byte[] resource) throws IOException {
Jar jar = m_analyzer.getJar();
jar.putResource(resourcePath, new ByteArrayResource(resource));
}
public void close() throws IOException {
// Write the iPOJO header (including manipulation metadata)
StringBuilder builder = new StringBuilder();
if (m_includeEmbedComponents) {
// Incorporate metadata of embed dependencies (if any)
for (Jar jar : m_analyzer.getClasspath()) {
try {
Manifest manifest = jar.getManifest();
Attributes main = manifest.getMainAttributes();
String components = Manifests.getComponents(main);
if (components != null) {
m_reporter.trace("Merging components from %s", jar.getName());
builder.append(components);
}
} catch (Exception e) {
m_reporter.warning("Cannot open MANIFEST of %s", jar.getName());
}
}
}
for (Element metadata : m_metadata) {
builder.append(m_renderer.render(metadata));
}
if (builder.length() != 0) {
m_analyzer.setProperty("IPOJO-Components", builder.toString());
}
// Add some mandatory imported packages
Attrs version = new Attrs();
version.put("version:Version", Constants.getPackageImportClause());
if (!m_analyzer.getReferred().containsFQN("org.apache.felix.ipojo")) {
m_analyzer.getReferred().put(m_analyzer.getPackageRef("org.apache.felix.ipojo"),
version);
}
if (!m_analyzer.getReferred().containsFQN("org.apache.felix.ipojo.architecture")) {
m_analyzer.getReferred().put(m_analyzer.getPackageRef("org.apache.felix.ipojo.architecture"),
version);
}
if (!m_analyzer.getReferred().containsFQN("org.osgi.service.cm")) {
Attrs cm = new Attrs();
cm.put("version:Version", "1.2");
m_analyzer.getReferred().put(m_analyzer.getPackageRef("org.osgi.service.cm"),
cm);
}
if (!m_analyzer.getReferred().containsFQN("org.osgi.service.log")) {
Attrs log = new Attrs();
log.put("version:Version", "1.3");
m_analyzer.getReferred().put(m_analyzer.getPackageRef("org.osgi.service.log"),
log);
}
}
public void setIncludeEmbedComponents(boolean excludeEmbedComponents) {
m_includeEmbedComponents = excludeEmbedComponents;
}
}