blob: 1367c13f21e123a6dbd6259e39e54def59a2ac01 [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.plugin;
import java.io.*;
import java.util.*;
import java.util.zip.ZipFile;
import java.util.zip.ZipEntry;
import org.apache.maven.archiver.*;
import org.apache.maven.artifact.*;
import org.apache.maven.plugin.*;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.jar.*;
import org.codehaus.plexus.util.FileUtils;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.felix.ipojo.manipulation.Manipulator;
import org.apache.felix.ipojo.manipulation.MethodDescriptor;
import org.apache.felix.ipojo.metadata.Attribute;
import org.apache.felix.ipojo.metadata.Element;
import org.apache.felix.ipojo.parser.ManifestMetadataParser;
import org.apache.felix.ipojo.parser.ParseException;
import org.apache.felix.ipojo.parser.XMLMetadataParser;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
/**
* Package an OSGi jar "bundle."
*
* @author <a href="mailto:felix-dev@incubator.apache.org">Apache Felix Project</a>
* @version $Rev$, $Date$
* @goal ipojo-bundle
* @phase package
* @requiresDependencyResolution runtime
* @description build an OSGi bundle jar
*/
public class OsgiJarMojo extends AbstractMojo {
public static final String OSGI_REFERENCES = "osgi.references";
public static final String AUTO_DETECT = "auto-detect";
private static final String[] EMPTY_STRING_ARRAY = {};
int bundleManifestVersion = 1;
/**
* Jars to Inline
*
* @parameter
*/
private List inlinedArtifacts = new ArrayList();
/**
* Packages to ignore when generating import-package header.
*
* @parameter
*/
private String ignorePackage;
/**
* The Maven project.
*
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
/**
* The directory for the generated JAR.
*
* @parameter expression="${project.build.directory}"
* @required
*/
private String buildDirectory;
/**
* The directory containing generated classes.
*
* @parameter expression="${project.build.outputDirectory}"
* @required
* @readonly
*/
private File outputDirectory;
/**
* The name of the generated JAR file.
*
* @parameter alias="jarName" expression="${project.build.finalName}"
* @required
*/
private String jarName;
/**
* The Jar archiver.
*
* @parameter expression="${component.org.codehaus.plexus.archiver.Archiver#jar}"
* @required
*/
private JarArchiver jarArchiver;
/**
* The maven archive configuration to use.
*/
private MavenArchiveConfiguration archiveConfig = new MavenArchiveConfiguration();
/**
* The comma separated list of tokens to include in the JAR. Default is
* '**'.
*
* @parameter alias="includes"
*/
private String jarSourceIncludes = "**";
/**
* The comma separated list of tokens to exclude from the JAR.
*
* @parameter alias="excludes"
*/
private String jarSourceExcludes;
/**
* @parameter
*/
private String manifestFile;
/**
* @parameter expression="${org.apache.felix.ipojo.tools.maven.plugin.OsgiManifest}"
*/
private OsgiManifest osgiManifest;
private String[][] namespaces;
private List referredPackages;
/**
* Execute this Mojo
*
* @throws MojoExecutionException
*/
public void execute() throws MojoExecutionException {
File jarFile = new File(buildDirectory, jarName + ".jar");
try {
performPackaging(jarFile);
}
catch (Exception e) {
throw new MojoExecutionException("Error assembling JAR bundle", e);
}
}
/**
* Generates the JAR bundle file.
*
* @param jarFile the target JAR file
* @throws IOException
* @throws ArchiverException
* @throws ManifestException
* @throws DependencyResolutionRequiredException
*/
private void performPackaging(File jarFile) throws IOException,
ArchiverException, ManifestException,
DependencyResolutionRequiredException, MojoExecutionException {
outputDirectory.mkdirs();
verifyDeclaredBundleManifestVersion();
getLog().info("Generating JAR bundle " + jarFile.getAbsolutePath());
MavenArchiver archiver = new MavenArchiver();
archiver.setArchiver(jarArchiver);
archiver.setOutputFile(jarFile);
addManifestFile();
addManifestEntries();
// Inline the contents of the indicated jar artifacts
inlineArtifacts();
// Add the JARs that were specified in the POM
// as "not" provided
addEmbeddedJars();
addBundleVersion();
// Insert iPOJO Manipulation
iPojoManipulation();
jarArchiver.addDirectory(outputDirectory, getIncludes(), getExcludes());
// Parse the output directory as if it was a JAR file.
// This creates special entries for classes, packageinfo
// and embedded JAR files (which are parsed as well).
Jar mainJar = new Jar(null, jarName, outputDirectory);
// Calculate the Bundle Classpath from the embedded
// JAR files. We hardcode the bcp as ., <embedded jars>
// TODO we add all the found JARs to the Bcp, maybe we
// should look if they are needed by traversing the imports.
List bundleClassPath = getBundleClassPath(mainJar);
bundleClassPath.add(0, ".");
createBundleClasspathHeader(bundleClassPath);
// Calculate the exports (contained) and imports (referred)
// The bundleClassPath contains the JARs in the right order
Set contained = new HashSet(); // package name
Set referred = new HashSet(); // package name
Map uses = new HashMap(); // package name => Set of package name
// Iterate over the bundle class path and calculate the contained
// and referred packages as well as the uses.
for (Iterator i = bundleClassPath.iterator(); i.hasNext();) {
String path = (String) i.next();
Jar jar = path.equals(".") ? mainJar : (Jar) mainJar.resources
.get(path);
analyzeJar(jar, contained, referred, uses);
}
referred.removeAll(contained);
// Check if the osgi.references property is set and display result
// if necessary.
checkReferencesProperty(uses);
// Dump referenced package information if debug logging is enabled.
if (getLog().isDebugEnabled()) {
printReferencedPackages(uses);
}
Map exports = parseHeader(osgiManifest.getExportPackage());
Map imports = parseHeader(osgiManifest.getImportPackage());
Map dynamicImports = parseHeader(osgiManifest.getDynamicImportPackage());
if (dynamicImports != null) {
// Remove any dynamic imports from the referred set.
referred = new HashSet(referred);
referred.removeAll(dynamicImports.keySet());
}
if (exports != null) {
verifyDeclaredExports(exports, contained);
createExportHeader(exports, uses);
}
// Remove any ignored packages from the referred set.
Set ignorePackage = parseIgnorePackage();
referred.removeAll(ignorePackage);
// If the POM file contains an import declaration,
// we verify its validity. Otherwise, we generate the
// import package header from the referred. Exports
// are added to automatically imports for R4 bundles.
if (imports == null) {
createImportHeader(referred, exports == null ? new HashSet()
: exports.keySet());
}
else {
verifyDeclaredImports(referred, imports);
}
//verifyBundleActivator(mainJar); // Replace it by setBundleActivator
archiver.createArchive(project, archiveConfig);
project.getArtifact().setFile(jarFile);
}
// private void verifyBundleActivator(Jar mainJar) {
// String ba = osgiManifest.getBundleActivator();
// if (ba == null || ba.trim().length() == 0) {
// switch ( mainJar.activators.size() ) {
// case 0: break;
// case 1: archiveConfig.addManifestEntry("Bundle-Activator", mainJar.activators.get(0));
// break;
// default:
// getLog().info("[OSGi] No Bundle-Activator specified and multiple found" );
// break;
// }
// }
// else {
// if( ! mainJar.activators.contains(ba))
// getLog().warn("[OSGi] UNABLE TO VERIFY BUNDLE ACTIVATOR: " + ba);
// }
// }
private void createBundleClasspathHeader(List bundleClassPath) {
StringBuffer sb = new StringBuffer();
for (Iterator i = bundleClassPath.iterator(); i.hasNext(); ) {
sb.append(i.next());
if (i.hasNext()) {
sb.append(",");
}
}
if (sb.length() > 0)
archiveConfig.addManifestEntry("Bundle-Classpath", sb.toString());
}
/**
* Iterate over the declared exports from the POM, verify that they are
* present, add the uses clause if necessary and finally add the manifest
* entry.
*
* @param contained Set of contained packages
* @param exports Map with the export clauses from the POM
* @throws MojoExecutionException
*/
void verifyDeclaredExports(Map exports, Set contained)
throws MojoExecutionException {
Set declaredExports = exports.keySet();
for (Iterator i = declaredExports.iterator(); i.hasNext();) {
String pack = (String) i.next();
if (!contained.contains(pack)) {
getLog()
.error("[OSGi] EXPORTED PACKAGE NOT IN BUNDLE: " + pack);
throw new MojoExecutionException(
"Exported Package not found in bundle or JARs on bundle class path "
+ pack);
}
}
}
/**
* Print out the export headers after adding the uses clause.
*
* @param exports
* @param uses
* @throws MojoExecutionException
*/
void createExportHeader(Map exports, Map uses)
throws MojoExecutionException {
if (exports.size() > 0) {
Set declaredExports = exports.keySet();
for (Iterator i = declaredExports.iterator(); i.hasNext();) {
String pack = (String) i.next();
Map clause = (Map) exports.get(pack);
if (bundleManifestVersion >= 2) {
Set t = (Set) uses.get(pack);
if (t != null && !t.isEmpty()) {
StringBuffer sb = new StringBuffer();
String del = "\"";
for (Iterator u = t.iterator(); u.hasNext();) {
String usedPackage = (String) u.next();
if (!usedPackage.equals(pack)) {
sb.append(del);
sb.append(usedPackage);
del = ",";
}
}
sb.append("\"");
clause.put("uses:", sb.toString());
}
}
}
archiveConfig.addManifestEntry(
"Export-Package",
printClauses(exports));
}
}
/**
* Verify that the declared imports match the referred packages.
*
* @param referred referred package
* @param imports imported packages from POM
* @throws MojoExecutionException
*/
void verifyDeclaredImports(Set referred, Map imports)
throws MojoExecutionException {
Set declaredImports = imports.keySet();
Set test = new HashSet(referred);
test.removeAll(declaredImports);
for (Iterator m = test.iterator(); m.hasNext();) {
Object o = m.next();
// For backwards compatibility with existing builds, only
// issue a warning for missing imports. Other the other hand,
// if packages are being ignored, then this is a new build
// so be more strict and throw an error.
if (osgiManifest.getIgnorePackage() == null) {
getLog().warn("[OSGi] MISSING IMPORT: " + o);
}
else {
getLog().error("[OSGi] MISSING IMPORT: " + o);
throw new MojoExecutionException("Missing Import " + o);
}
}
test = new HashSet(declaredImports);
test.removeAll(referred);
for (Iterator m = test.iterator(); m.hasNext();) {
getLog().warn("[OSGi] SUPERFLUOUS IMPORT: " + m.next());
getLog()
.warn(
"[OSGi] Removing the POM Import-Package element will automatically generate the import clauses");
}
}
/**
* Standard OSGi header parser. This parser can handle the format clauses
* ::= clause ( ',' clause ) + clause ::= name ( ';' name ) (';' key '='
* value )
*
* This is mapped to a Map { name => Map { attr|directive => value } }
*
* @param value
* @return
* @throws MojoExecutionException
*/
static Map parseHeader(String value) throws MojoExecutionException {
if (value == null || value.trim().length() == 0)
return null;
Map result = new HashMap();
QuotedTokenizer qt = new QuotedTokenizer(value, ";=,");
char del;
do {
boolean hadAttribute = false;
Map clause = new HashMap();
List aliases = new ArrayList();
aliases.add(qt.nextToken());
del = qt.getSeparator();
while (del == ';') {
String adname = qt.nextToken();
if ((del = qt.getSeparator()) != '=') {
if (hadAttribute)
throw new MojoExecutionException(
"Header contains name field after attribute or directive: "
+ adname + " from " + value);
aliases.add(adname);
}
else {
String advalue = qt.nextToken();
clause.put(adname, advalue);
del = qt.getSeparator();
hadAttribute = true;
}
}
for (Iterator i = aliases.iterator(); i.hasNext();) {
result.put(i.next(), clause);
}
} while (del == ',');
return result;
}
/**
* Create the import header, taking into account R4 automatic import clauses
* for the exports.
*
* @param referred
* @param contained
*/
void createImportHeader(Set referred, Set contained) {
// Add handler import
for(int j = 0; j < namespaces.length; j++) {
for(int k = 0; k < namespaces[j].length; k++) {
if(!namespaces[j][k].equals("")) {
int lastIndex = namespaces[j][k].lastIndexOf('.');
String ns = namespaces[j][k].substring(0, lastIndex);
referred.add(ns);
}
}
}
// Add refered imports form the metadata
for(int i = 0; i < referredPackages.size(); i++) {
String pack = (String) referredPackages.get(i);
referred.add(pack);
}
// Add org.apache.felix.ipojo, org.apache.felix.ipojo.architecture is not already in the set
referred.add(IPojoPluginConfiguration.ipojo_package);
referred.add(IPojoPluginConfiguration.ipojo_arch_package);
referred.add(IPojoPluginConfiguration.config_admin_package);
if (referred.isEmpty())
return;
referred = new TreeSet(referred);
if (bundleManifestVersion > 1) {
referred.addAll(contained);
}
StringBuffer sb = new StringBuffer();
String del = "";
for (Iterator i = referred.iterator(); i.hasNext();) {
sb.append(del);
sb.append(i.next());
del = ", ";
}
archiveConfig.addManifestEntry("Import-Package", sb.toString());
getLog().info("Set Imports to : " + sb.toString());
}
/**
* Calculate the bundle class path based on the list of JARs in our bundle.
* This list includes outselves. We also calculate the Bundle-Classpath
* header (a bit clumsy) This is a bit cheap, so maybe this needs to be
* changed
*
* @param mainJar
* @return
*/
List getBundleClassPath(Jar mainJar) {
List result = new ArrayList();
for (Iterator i = mainJar.resources.keySet().iterator(); i.hasNext();) {
String path = (String) i.next();
Object resource = mainJar.resources.get(path);
if (resource instanceof Jar) {
result.add(path);
}
}
return result;
}
/**
* We traverse through al the classes that we can find and calculate the
* contained and referred set and uses.
*
* @param jar
* @param contained
* @param referred
* @param uses
*/
void analyzeJar(Jar jar, Set contained, Set referred, Map uses) {
String prefix = "";
Set set = jar.getEntryPaths(prefix);
for (Iterator r = set.iterator(); r.hasNext();) {
String path = (String) r.next();
Object resource = jar.getEntry(path);
if (resource instanceof Clazz) {
Clazz clazz = (Clazz) resource;
String pathOfClass = path.substring(prefix.length());
String pack = Clazz.getPackage(pathOfClass);
contained.add(pack);
referred.addAll(clazz.getReferred());
// Add all the used packages
// to this package
Set t = (Set) uses.get(pack);
if (t == null)
uses.put(pack, t = new HashSet());
t.addAll(clazz.getReferred());
t.remove(pack);
}
}
}
/**
* Print a standard Map based OSGi header.
*
* @param exports map { name => Map { attribute|directive => value } }
* @return the clauses
*/
String printClauses(Map exports) {
StringBuffer sb = new StringBuffer();
String del = "";
for (Iterator i = exports.keySet().iterator(); i.hasNext();) {
String name = (String) i.next();
Map map = (Map) exports.get(name);
sb.append(del);
sb.append(name);
for (Iterator j = map.keySet().iterator(); j.hasNext();) {
String key = (String) j.next();
String value = (String) map.get(key);
sb.append(";");
sb.append(key);
sb.append("=");
sb.append(value);
}
del = ", ";
}
return sb.toString();
}
/**
* Check if the BundleManifest version is set correctly, base the manifest
* version on it.
*
* @throws MojoExecutionException
*/
void verifyDeclaredBundleManifestVersion() throws MojoExecutionException {
String mfv = osgiManifest.getBundleManifestVersion();
if (mfv != null && mfv.trim().length() != 0) {
try {
bundleManifestVersion = Integer.parseInt(mfv);
if (bundleManifestVersion != 2)
throw new MojoExecutionException(
"Bundle-ManifestVersion must be 2, it is " + mfv);
}
catch (Exception e) {
throw new MojoExecutionException(
"Bundle-ManifestVersion must be an integer: " + mfv);
}
}
}
/**
* TODO: Decide if we accept merging of entire manifest.mf files Here's a
* big question to make a final decision at some point: Do accept merging of
* manifest entries located in some file somewhere in the project directory?
* If so, do we allow both file and configuration based entries to be
* specified simultaneously and how do we merge these?
*/
private void addManifestFile() {
if (manifestFile != null) {
File file = new File(project.getBasedir().getAbsolutePath(),
manifestFile);
getLog().info(
"Manifest file: " + file.getAbsolutePath()
+ " will be used");
archiveConfig.setManifestFile(file);
}
else {
getLog().info("No manifest file specified. Default will be used.");
}
}
/**
* Look for any OSGi specified manifest entries in the maven-osgi-plugin
* configuration section of the POM. If we find some, then add them to the
* target artifact's manifest.
*/
private void addManifestEntries() {
if (osgiManifest.getBundleVersion() == null) {
addBundleVersion();
}
if (osgiManifest != null && osgiManifest.getEntries().size() > 0) {
Map entries = osgiManifest.getEntries();
getLog().debug(
"Bundle manifest will be modified with the following entries: "
+ entries.toString());
archiveConfig.addManifestEntries(entries);
}
else {
getLog()
.info(
"No OSGi bundle manifest entries have been specified in the POM.");
}
}
/**
* We are going to iterate through the POM's specified JAR dependencies. If
* a dependency has a scope of either RUNTIME or COMPILE, then we'll JAR
* them up inside the OSGi bundle artifact. We will then add the
* Bundle-Classpath manifest entry.
*
* Artifacts which are inlined will not be included.
*/
private void addEmbeddedJars() throws MojoExecutionException {
Set artifacts = project.getArtifacts();
for (Iterator it = artifacts.iterator(); it.hasNext();) {
Artifact artifact = (Artifact) it.next();
if (!Artifact.SCOPE_PROVIDED.equals(artifact.getScope())
&& !Artifact.SCOPE_TEST.equals(artifact.getScope())) {
String type = artifact.getType();
if ("jar".equals(type)) {
// Do not include artifacts which are inlined
if (!(inlinedArtifacts.contains(artifact.getArtifactId()))) {
File depFile = artifact.getFile();
try {
FileUtils.copyFileToDirectory(depFile, outputDirectory);
}
catch (Exception e) {
String errmsg = "Error copying "
+ depFile.getAbsolutePath() + " to "
+ outputDirectory.getAbsolutePath();
throw new MojoExecutionException(errmsg, e);
}
}
}
}
}
}
/**
* Auto-set the bundle version.
*/
private void addBundleVersion() {
// Maven uses a '-' to separate the version qualifier,
// while OSGi uses a '.', so we need to convert to a '.'
String version = project.getVersion().replace('-', '.');
osgiManifest.setBundleVersion(version);
}
/**
* Returns a string array of the includes to be used when assembling/copying
* the war.
*
* @return an array of tokens to include
*/
private String[] getIncludes() {
return new String[] {jarSourceIncludes};
}
/**
* Returns a string array of the excludes to be used when assembling/copying
* the jar.
*
* @return an array of tokens to exclude
*/
private String[] getExcludes() {
List excludeList = new ArrayList(FileUtils.getDefaultExcludesAsList());
if (jarSourceExcludes != null && !"".equals(jarSourceExcludes)) {
excludeList.add(jarSourceExcludes);
}
return (String[]) excludeList.toArray(EMPTY_STRING_ARRAY);
}
private Set parseIgnorePackage() {
HashSet result = new HashSet();
if ((ignorePackage == null) && (osgiManifest.getIgnorePackage() != null)) {
ignorePackage = osgiManifest.getIgnorePackage();
getLog().warn("DEPRECATED METADATA! "
+ "The <ignorePackage> tag should be set inside the <configuration> "
+ "tag, not in the <osgiManifest> tag.");
}
if (ignorePackage != null) {
StringTokenizer st = new StringTokenizer(ignorePackage, ",", false);
while (st.hasMoreTokens()) {
result.add(st.nextToken().trim());
}
}
return result;
}
private void checkReferencesProperty(Map uses) {
String interestedIn = System.getProperty(OSGI_REFERENCES);
if (interestedIn == null) {
return;
}
StringBuffer buf = new StringBuffer();
Iterator it1 = uses.entrySet().iterator();
while (it1.hasNext()) {
Map.Entry entry = (Map.Entry) it1.next();
String pack = (String) entry.getKey();
Set references = (Set) entry.getValue();
Iterator it2 = references.iterator();
while (it2.hasNext()) {
String packReferred = (String) it2.next();
if (interestedIn.equals(packReferred)) {
buf.append(" |-- ");
buf.append(pack);
buf.append('\n');
break;
}
}
}
if (buf.length() == 0) {
getLog().info("Noone uses " + interestedIn);
}
else {
int changePos = buf.lastIndexOf("|");
buf.setCharAt(changePos, '+');
getLog().info(interestedIn + " used by;\n" + buf);
}
}
private void printReferencedPackages(Map uses) {
StringBuffer buf = new StringBuffer();
Iterator it1 = uses.entrySet().iterator();
while (it1.hasNext()) {
Map.Entry entry = (Map.Entry) it1.next();
String pack = (String) entry.getKey();
buf.append(pack);
buf.append('\n');
Set references = (Set) entry.getValue();
Iterator it2 = references.iterator();
while (it2.hasNext()) {
String packReferred = (String) it2.next();
buf.append(" |-- ");
buf.append(packReferred);
buf.append('\n');
}
int changePos = buf.lastIndexOf("|");
if (changePos >= 0) {
buf.setCharAt(changePos, '+');
}
buf.append('\n');
}
getLog().debug("Referenced package list: \n" + buf.toString());
}
private void inlineArtifacts() throws MojoExecutionException {
Set artifacts = project.getArtifacts();
for (Iterator it = artifacts.iterator(); it.hasNext();) {
Artifact artifact = (Artifact) it.next();
if (!Artifact.SCOPE_PROVIDED.equals(artifact.getScope())
&& !Artifact.SCOPE_TEST.equals(artifact.getScope())) {
String type = artifact.getType();
if ("jar".equals(type)) {
if ((inlinedArtifacts.contains(artifact.getArtifactId()))) {
File depFile = artifact.getFile();
try {
ZipFile inlinedJar = new ZipFile(depFile);
Enumeration entries = inlinedJar.entries();
byte[] buffer = new byte[4096];
while (entries.hasMoreElements()) {
ZipEntry entry = (ZipEntry) entries.nextElement();
if (entry.isDirectory()) {
new File(outputDirectory, entry.getName()).mkdirs();
} else {
// Have to do this because some JARs ship without directories, i.e., just files.
new File(outputDirectory, entry.getName()).getParentFile().mkdirs();
FileOutputStream out = new FileOutputStream(new File(outputDirectory, entry.getName()));
InputStream in = inlinedJar.getInputStream(entry);
for (int read = in.read(buffer); read != -1; read = in.read(buffer)) {
out.write(buffer, 0, read);
}
in.close();
out.close();
}
}
} catch (Exception e) {
String errmsg = "Error inlining "
+ depFile.getAbsolutePath() + " to "
+ outputDirectory.getAbsolutePath();
throw new MojoExecutionException(errmsg, e);
}
}
}
}
}
}
// ===== iPOJO's methods =====
private Element[] parseXMLMetadata(String path) throws MojoExecutionException {
File metadata = new File(outputDirectory+path);
URL url;
Element[] meta = null;
try {
url = metadata.toURI().toURL();
if (url == null) {
getLog().error("No metadata at : " + outputDirectory+path);
throw new MojoExecutionException("[iPOJO] No metadata at : " + outputDirectory+path);
}
InputStream stream = url.openStream();
XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
XMLMetadataParser handler = new XMLMetadataParser();
parser.setContentHandler(handler);
InputSource is = new InputSource(stream);
parser.parse(is);
meta = handler.getMetadata();
referredPackages = handler.getReferredPackages();
} catch (MalformedURLException e) {
getLog().error("Malformed URL for " + outputDirectory+path+ "("+e.getMessage()+")");
throw new MojoExecutionException("[iPOJO] Malformed URL for " + outputDirectory+path);
} catch (IOException e) {
getLog().error("Cannot open the file : " + outputDirectory+path + "("+e.getMessage()+")");
throw new MojoExecutionException("[iPOJO] Cannot open the file : " + outputDirectory+path);
} catch (Exception e) {
getLog().error("Parsing Error when parsing the XML file " + outputDirectory+path+ "("+e.getMessage()+")");
throw new MojoExecutionException("[iPOJO] Parsing Error when parsing the XML file " + outputDirectory+path);
}
if(meta == null || meta.length == 0) {
getLog().error("No component in " + outputDirectory+path); //TODO : change the message
throw new MojoExecutionException("[iPOJO] No component in " + outputDirectory+path);
}
return meta;
}
private Element[] parseManifestMetadata(String metadata) throws MojoExecutionException {
Element[] components = null;
ManifestMetadataParser parser = new ManifestMetadataParser();
try {
parser.parse(metadata);
components = parser.getComponentsMetadata();
} catch (ParseException e) {
getLog().error("Parsing Error when parsing the Manifest metadata " + metadata + "("+e.getMessage()+")");
throw new MojoExecutionException("[iPOJO] Parsing Error when parsing the Manifest metadata " + metadata);
}
if(components == null || components.length == 0) {
getLog().error("No component in " + metadata);
throw new MojoExecutionException("[iPOJO] No component in " + metadata);
}
return components;
}
private void iPojoManipulation() throws MojoExecutionException {
//Try to read the content of a file of the ouptut directory
getLog().info("iPOJO Manipulation ...");
Element[] original_meta = null;
// Get the metadata.xml location
String path = (String) osgiManifest.getEntries().get("iPOJO-Metadata");
if(path != null) {
if(!path.startsWith("/")) { path = "/" + path; }
original_meta = parseXMLMetadata(path);
} else {
String meta_ = (String) osgiManifest.getEntries().get("iPOJO-Components");
if(meta_ != null) {
original_meta = parseManifestMetadata(meta_);
} else {
getLog().error("Neither iPOJO-Metadata nor iPOJO-Components are in the manifest, please in the osgi-bundle packaging instead og ipojo-bundle");
throw new MojoExecutionException("[iPOJO] Neither iPOJO-Metadata nor iPOJO-Components are in the manifest");
}
}
Manipulator manipulator = new Manipulator();
String[] metadata = new String[original_meta.length];
String meta = "";
if(namespaces == null) { namespaces = new String[original_meta.length][]; } //NO
for(int i = 0; i < original_meta.length; i++) {
if(original_meta[i].getName().equalsIgnoreCase("component")) {
namespaces[i] = original_meta[i].getNamespaces();
try {
manipulator.preProcess(original_meta[i].getAttribute("className"), outputDirectory);
} catch (Exception e) {
getLog().error("Manipulation error in the class : " + original_meta[i].getAttribute("className") + "("+e.getMessage()+")");
throw new MojoExecutionException("[iPOJO] Manipulation error in the class : " + original_meta[i].getAttribute("className"));
}
// Insert information to metadata
Element elem = new Element("Manipulation", "");
for(int j = 0; j < manipulator.getInterfaces().length; j++) {
// Create an interface element for each implemented interface
Element itf = new Element("Interface", "");
Attribute att =new Attribute("name", manipulator.getInterfaces()[j]);
itf.addAttribute(att);
elem.addElement(itf);
}
for(Iterator it = manipulator.getFields().keySet().iterator(); it.hasNext(); ) {
Element field = new Element("Field", "");
String name = (String) it.next();
String type = (String) manipulator.getFields().get(name);
Attribute attName =new Attribute("name", name);
Attribute attType =new Attribute("type", type);
field.addAttribute(attName);
field.addAttribute(attType);
elem.addElement(field);
}
for(int j= 0; j < manipulator.getMethods().size(); j++) {
MethodDescriptor method = (MethodDescriptor) manipulator.getMethods().get(j);
elem.addElement(method.getElement());
}
original_meta[i].addElement(elem);
} else { namespaces[i] = new String[0]; }
// Transform the metadate to manifest metadata
metadata[i] = buildManifestMetadata(original_meta[i], "");
meta = meta + metadata[i];
}
archiveConfig.addManifestEntry("iPOJO-Components", meta);
setBundleActivator();
getLog().info("iPOJO Packaging ... SUCCESS");
}
private String buildManifestMetadata(Element element, String actual) {
String result="";
if(element.getNameSpace().equals("")) { result = actual + element.getName() + " { "; }
else { result = actual + element.getNameSpace()+":"+element.getName() + " { "; }
for(int i = 0; i < element.getAttributes().length; i++) {
if(element.getAttributes()[i].getNameSpace().equals("")) {
result = result + "$" + element.getAttributes()[i].getName() + "=\""+element.getAttributes()[i].getValue() + "\" ";
}
else {
result = result + "$" + element.getAttributes()[i].getNameSpace()+ ":" + element.getAttributes()[i].getName() + "=\""+element.getAttributes()[i].getValue() + "\" ";
}
}
for(int i = 0; i < element.getElements().length; i++) {
result = buildManifestMetadata(element.getElements()[i], result);
}
return result +"}";
}
private void setBundleActivator() throws MojoExecutionException {
archiveConfig.addManifestEntry("Bundle-Activator", "org.apache.felix.ipojo.Activator");
}
}