/*
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2004
* Copyright by ESO (in the framework of the ALMA collaboration),
* All rights reserved
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package alma.acs.eclipse.utils.pluginbuilder;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Vector;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.logging.Logger;
import alma.acs.eclipse.utils.jar.JarFileHelper;
import alma.acs.eclipse.utils.jar.JarFolder;
/**
* Write the <code>MANIFEST>MF</code> of the plugin
*
* @author acaproni
*
*/
public class ManifestWriter {
/**
* The logger
*/
private final Logger logger;
/**
* The manifest that objects from this class write in the pugin folder
*/
private final Manifest manifest = new Manifest();
/**
* The name of the manifest file
*/
private static final String manifestName = "MANIFEST.MF";
/**
* The folder to write the manifest into
*/
private final File manifestFolder;
/**
* The root folder of the plugin
*/
private final File pluginFolder;
/**
* The bundle name is dynamically generated by appending <code>pluginBundleName</code>
* to the plugin root name
*/
private static final String pluginBundleName=" ACS Plug-in";
/**
* The attribute name for Bundle-ManifestVersion
*/
private final Attributes.Name bundleManifestVersionName = new Attributes.Name("Bundle-ManifestVersion");
/**
* The attribute name for Bundle-SymbolicName
*/
private final Attributes.Name bundleSymbolicName = new Attributes.Name("Bundle-SymbolicName");
/**
* The attribute name for Bundle-ActivationPolicy
* <P>
* This is also used to add dependencies
*/
private final Attributes.Name bundleActivationPolicyName= new Attributes.Name("Bundle-ActivationPolicy");
/**
* The attribute name for Bundle-ActivationPolicy
*/
private final Attributes.Name requireBundleName= new Attributes.Name("Require-bundle");
/**
* The activation policy
*/
public static final String activationPolicy = "lazy";
/**
* The attribute name for Bundle-Name
*/
private final Attributes.Name bundleName = new Attributes.Name("Bundle-Name");
/**
* The attribute name for Bundle-Vendor
*/
private final Attributes.Name bundleVendorName= new Attributes.Name("Bundle-Vendor");
/**
* The attribute name for Bundle-Version
*/
private final Attributes.Name bundleVersionName= new Attributes.Name("Bundle-Version");
/**
* The bundle version
*/
private String bundleVersion;
/**
* The attribute name for Bundle-ClassPath
* (i.e. the list of ACS jar files in the plugin).
* <P>
* The classpath is built by reading the jar files in the plugin folder
*/
private final Attributes.Name bundleClasspathName= new Attributes.Name("Bundle-ClassPath");
/**
* The attribute name for Export-Package
* (i.e. the list of java packages exported by all the jar files contained in the
* plugin)
* <P>
* The export package is built be reading, for each jar file in the plugin root
* folder, the list of the java packages
*/
private final Attributes.Name exportPackageName= new Attributes.Name("Export-Package");
/** Used when doing bundling by reference */
private boolean bundlingByReference;
private String[] finalJarsLocations;
/**
* The dependencies of this plugin
*/
private final String[] dependencies;
/**
* The vendor i.e ESO
*/
private static final String vendor = "European Southern Observatory";
/**
* Constructor
*
* @param folder The folder to write the manifest into
* @param pluginFolder The root folder of the plugin
* @param finalJarsLocations
* @param bundleByReference
* @param dependencies The plugins this plugin depends on
* @param Logger The logger
*/
public ManifestWriter(
File folder,
File pluginFolder,
boolean bundleByReference,
String[] finalJarsLocations,
String[] dependencies,
String bundleVersion,
Logger logger) {
if (folder==null || !folder.canWrite()) {
throw new IllegalArgumentException("Invalid folder for the manifest");
}
if (pluginFolder==null || !pluginFolder.canRead()) {
throw new IllegalArgumentException("Invalid plugin folder");
}
if (logger==null) {
throw new IllegalArgumentException("The logger can't be null");
}
this.bundlingByReference = bundleByReference;
this.finalJarsLocations = finalJarsLocations;
this.dependencies=dependencies;
if (bundleVersion != null && !bundleVersion.trim().isEmpty()) {
this.bundleVersion = bundleVersion;
}
else {
this.bundleVersion = "1.0.0";
}
this.logger=logger;
manifestFolder=folder;
this.pluginFolder=pluginFolder;
}
/**
* Set the attributes of the manifest
*
* @param attrs The attributes
* @throws Exception In case of error
*/
private void setAttributes(Attributes attrs) throws Exception {
if (attrs==null) {
throw new IllegalArgumentException("the attributes can't be null");
}
attrs.clear();
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
attrs.put(bundleManifestVersionName, "2");
attrs.put(bundleName, pluginFolder.getName()+pluginBundleName);
attrs.put(bundleSymbolicName, pluginFolder.getName()+"; singleton=true");
attrs.put(bundleVersionName, bundleVersion);
attrs.put(bundleVendorName, vendor);
attrs.put(bundleActivationPolicyName,activationPolicy);
// Add the classpath i.e. the jar files in the root plugin folder
JarFolder pluginJarFolder = new JarFolder(pluginFolder);
// String acsroot = System.getenv("ACSROOT");
// String introot = System.getenv("INTROOT");
String[] jars = null;
if( bundlingByReference )
jars = finalJarsLocations;
else
jars = pluginJarFolder.getJars();
StringBuilder classpath = new StringBuilder();
if (jars!=null && jars.length>0) {
for (int t=0; t<jars.length; t++) {
// If we are bundling by reference, then write the reference, no the actual jarfile
if( bundlingByReference ) {
// String tmp = "";
String prefix = "external:";
// if( jars[t].contains( acsroot ) ) {
// tmp = jars[t].replaceAll(acsroot, "");
// prefix = "external:$ACSROOT$/";
// }
// else if( jars[t].contains( introot ) ) {
// tmp = jars[t].replaceAll(introot, "");
// prefix = "external:$INTROOT$/";
// }
classpath.append(prefix);
// classpath.append(tmp);
classpath.append(jars[t]);
}
else
classpath.append(jars[t]);
if (t<jars.length-1)
classpath.append(", ");
logger.finer("Adding "+jars[t]+" to "+bundleClasspathName+" attribute of "+manifestName);
}
attrs.put(bundleClasspathName, classpath.toString());
}
// Add the exported java packages
Vector<String> javaPkgs = new Vector<String>();
for (int i=0; i!= jars.length; i++) {
File jarFile = null;
if( bundlingByReference ) {
jarFile = new File(jars[i]);
}
else
jarFile = new File(pluginFolder.getAbsolutePath()+File.separator+jars[i]);
JarFileHelper jarFileHelper = new JarFileHelper(jarFile);
int n=jarFileHelper.getPackages(javaPkgs);
if (n>0) {
logger.finer("Found "+n+" java packages in "+jars[i]);
} else {
logger.warning("Found "+n+" java packages in "+jars[i]);
}
}
StringBuilder pkgs = new StringBuilder();
if (javaPkgs.size()>0) {
for (int t=0; t<javaPkgs.size(); t++) {
pkgs.append(javaPkgs.elementAt(t));
if (t<javaPkgs.size()-1) {
pkgs.append(',');
pkgs.append(' ');
}
logger.finer("Adding "+javaPkgs.elementAt(t)+" to "+exportPackageName+" attribute of "+manifestName);
}
attrs.put(exportPackageName,pkgs.toString());
}
// Add the dependencies if any
StringBuilder deps = new StringBuilder("system.bundle");
for (String dep: dependencies) {
deps.append(',');
deps.append(' ');
if (dep.contains("_")) {
// a version is present
String[] tmp=dep.split("_");
deps.append(tmp[0]);
deps.append(";bundle-version=\"");
deps.append(tmp[1]);
deps.append('\"');
} else {
deps.append(dep);
}
}
attrs.put(requireBundleName, deps.toString());
}
/**
* Write the manifest
*
* @throws Exception In case of error
*/
public void write() throws Exception {
File manifestFile = new File(manifestFolder.getAbsolutePath()+File.separator+manifestName);
FileOutputStream outStream = new FileOutputStream(manifestFile,false);
Attributes attributes = manifest.getMainAttributes();
setAttributes(attributes);
manifest.write(outStream);
}
}