/* * 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; } }