| /* |
| * 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.dm.annotation.plugin.bnd; |
| |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import aQute.bnd.service.AnalyzerPlugin; |
| import aQute.bnd.service.Plugin; |
| import aQute.bnd.osgi.Analyzer; |
| import aQute.bnd.osgi.Resource; |
| import aQute.service.reporter.Reporter; |
| |
| /** |
| * This class is a BND plugin. It scans the target bundle and look for DependencyManager annotations. |
| * It can be directly used when using ant and can be referenced inside the ".bnd" descriptor, using |
| * the "-plugin" parameter. |
| * |
| * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> |
| */ |
| public class AnnotationPlugin implements AnalyzerPlugin, Plugin |
| { |
| private static final String IMPORT_SERVICE = "Import-Service"; |
| private static final String EXPORT_SERVICE = "Export-Service"; |
| private BndLogger m_logger; |
| private Reporter m_reporter; |
| private boolean m_buildImportExportService; |
| |
| /** |
| * This plugin is called after analysis of the JAR but before manifest |
| * generation. When some DM annotations are found, the plugin will add the corresponding |
| * DM component descriptors under META-INF/ directory. It will also set the |
| * "DependencyManager-Component" manifest header (which references the descriptor paths). |
| * |
| * @param analyzer the object that is used to retrieve classes containing DM annotations. |
| * @return true if the classpath has been modified so that the bundle classpath must be reanalyzed |
| * @throws Exception on any errors. |
| */ |
| public boolean analyzeJar(Analyzer analyzer) throws Exception |
| { |
| analyzer.setExceptions(true); |
| try { |
| // We'll do the actual parsing using a DescriptorGenerator object. |
| DescriptorGenerator generator = new DescriptorGenerator(analyzer, m_logger); |
| |
| if (generator.execute()) |
| { |
| // We have parsed some annotations: set the OSGi "DependencyManager-Component" header in the target bundle. |
| analyzer.setProperty("DependencyManager-Component", generator.getDescriptorPaths()); |
| |
| // Possibly set the Import-Service/Export-Service header |
| if (m_buildImportExportService) |
| { |
| // Don't override Import-Service header, if it is found from the bnd directives. |
| if (analyzer.getProperty(IMPORT_SERVICE) == null) |
| { |
| buildImportExportService(analyzer, IMPORT_SERVICE, generator.getImportService()); |
| } |
| |
| // Don't override Export-Service header, if already defined |
| if (analyzer.getProperty(EXPORT_SERVICE) == null) |
| { |
| buildImportExportService(analyzer, EXPORT_SERVICE, generator.getExportService()); |
| } |
| } |
| |
| // And insert the generated descriptors into the target bundle. |
| Map<String, Resource> resources = generator.getDescriptors(); |
| for (Map.Entry<String, Resource> entry : resources.entrySet()) |
| { |
| analyzer.getJar().putResource(entry.getKey(), entry.getValue()); |
| } |
| |
| // Insert the metatype resource, if any. |
| Resource metaType = generator.getMetaTypeResource(); |
| if (metaType != null) |
| { |
| analyzer.getJar().putResource("OSGI-INF/metatype/metatype.xml", metaType); |
| } |
| } |
| } |
| |
| catch (Throwable t) |
| { |
| m_logger.error(parse(t)); |
| } |
| |
| // Collect all logs and write it into the analyzer. |
| m_logger.getLogs(analyzer); |
| |
| // When some errors are present in the analyzer logs: it seems that the Bnd ANT task |
| // does not report it. So, to work around, we just log the errors ourself, and |
| // we throw an Error in case some errors are detected, in order to prevent the bnd ANT |
| // task from generating the target bundle. |
| if (analyzer.getWarnings().size() > 0) |
| { |
| for (Iterator<String> e = analyzer.getWarnings().iterator(); e.hasNext();) |
| { |
| System.out.println(e.next()); |
| } |
| analyzer.getWarnings().clear(); |
| } |
| |
| if (analyzer.getErrors().size() > 0) |
| { |
| for (Iterator<String> e = analyzer.getErrors().iterator(); e.hasNext();) |
| { |
| System.err.println(e.next()); |
| } |
| analyzer.getErrors().clear(); |
| throw new Error("DM Annotation plugin failure"); |
| } |
| return false; |
| } |
| |
| private void buildImportExportService(Analyzer analyzer, String header, Set<String> services) |
| { |
| m_logger.info("building %s header with the following services: %s", header, services); |
| if (services.size() > 0) |
| { |
| StringBuilder sb = new StringBuilder(); |
| for (String service : services) |
| { |
| sb.append(service); |
| sb.append(","); |
| } |
| sb.setLength(sb.length() - 1); // skip last comma |
| analyzer.setProperty(header, sb.toString()); |
| } |
| } |
| |
| public void setProperties(Map<String, String> map) |
| { |
| String logLevel = map.get("log"); |
| m_logger = new BndLogger(logLevel == null ? "error" : logLevel); |
| String generateImportExportService = map.get("build-import-export-service"); |
| if (generateImportExportService == null) |
| { |
| generateImportExportService = "true"; |
| } |
| m_buildImportExportService = Boolean.parseBoolean(generateImportExportService); |
| } |
| |
| public void setReporter(Reporter reporter) |
| { |
| m_reporter = reporter; |
| } |
| |
| /** |
| * Parse an exception into a string. |
| * @param e The exception to parse |
| * @return the parsed exception |
| */ |
| private static String parse(Throwable e) { |
| StringWriter buffer = new StringWriter(); |
| PrintWriter pw = new PrintWriter(buffer); |
| e.printStackTrace(pw); |
| return (buffer.toString()); |
| } |
| } |