blob: accf7190af37b5775caed14ddaf2559bbdb9cf6f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.core.runtime.adaptor;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.eclipse.osgi.framework.internal.defaultadaptor.DevClassPathHelper;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.service.pluginconversion.PluginConverter;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
public class PluginConverterImpl implements PluginConverter, IModel {
private BundleContext context;
private BufferedWriter out;
private IPluginInfo pluginInfo;
private File pluginManifestLocation;
private Dictionary generatedManifest;
private static final String MANIFEST_VERSION = "Manifest-Version";
private static final String PLUGIN_PROPERTIES_FILENAME = "plugin";
private static final String PI_ECLIPSE_OSGI = "org.eclipse.osgi";
private static PluginConverterImpl instance;
private static final String[] ARCH_LIST = {org.eclipse.osgi.service.environment.Constants.ARCH_PA_RISC, org.eclipse.osgi.service.environment.Constants.ARCH_PPC, org.eclipse.osgi.service.environment.Constants.ARCH_SPARC, org.eclipse.osgi.service.environment.Constants.ARCH_X86, org.eclipse.osgi.service.environment.Constants.ARCH_AMD64};
private static final String FRAGMENT_MANIFEST = "fragment.xml"; //$NON-NLS-1$
private static final String GENERATED_FROM = "Generated-from"; //$NON-NLS-1$
private static final String LEGACY = "Legacy"; //$NON-NLS-1$
private static final String[] OS_LIST = {org.eclipse.osgi.service.environment.Constants.OS_AIX, org.eclipse.osgi.service.environment.Constants.OS_HPUX, org.eclipse.osgi.service.environment.Constants.OS_LINUX, org.eclipse.osgi.service.environment.Constants.OS_MACOSX, org.eclipse.osgi.service.environment.Constants.OS_QNX, org.eclipse.osgi.service.environment.Constants.OS_SOLARIS, org.eclipse.osgi.service.environment.Constants.OS_WIN32};
protected static final String PI_RUNTIME = "org.eclipse.core.runtime"; //$NON-NLS-1$
protected static final String PI_BOOT = "org.eclipse.core.boot"; //$NON-NLS-1$
protected static final String PI_RUNTIME_COMPATIBILITY = "org.eclipse.core.runtime.compatibility"; //$NON-NLS-1$
private static final String PLUGIN = "Plugin-Class"; //$NON-NLS-1$
private static final String PLUGIN_MANIFEST = "plugin.xml"; //$NON-NLS-1$
private static final String COMPATIBILITY_ACTIVATOR = "org.eclipse.core.internal.compatibility.PluginActivator"; //$NON-NLS-1$
private static final String[] WS_LIST = {org.eclipse.osgi.service.environment.Constants.WS_CARBON, org.eclipse.osgi.service.environment.Constants.WS_GTK, org.eclipse.osgi.service.environment.Constants.WS_MOTIF, org.eclipse.osgi.service.environment.Constants.WS_PHOTON, org.eclipse.osgi.service.environment.Constants.WS_WIN32};
public static PluginConverterImpl getDefault() {
return instance;
}
public PluginConverterImpl() {
this(null);
}
PluginConverterImpl(BundleContext context) {
this.context = context;
instance = this;
}
private void init(){
// need to make sure these fields are cleared out for each conversion.
out=null;
pluginInfo=null;
pluginManifestLocation=null;
generatedManifest = new Hashtable(10);
}
private void fillPluginInfo(File pluginBaseLocation) {
pluginManifestLocation = pluginBaseLocation;
if (pluginManifestLocation == null)
return;
URL pluginFile = findPluginManifest(pluginBaseLocation);
if (pluginFile == null)
return;
try {
pluginInfo = parsePluginInfo(pluginFile);
} catch (PluginConversionException e) {
FrameworkLogEntry entry = new FrameworkLogEntry(PI_ECLIPSE_OSGI, e.getMessage(), 0, e, null);
EclipseAdaptor.getDefault().getFrameworkLog().log(entry);
}
}
public synchronized File convertManifest(File pluginBaseLocation, File bundleManifestLocation, boolean compatibilityManifest) {
init();
fillPluginInfo(pluginBaseLocation);
if (pluginInfo == null)
return null;
if (bundleManifestLocation==null) {
String cacheLocation = (String) System.getProperties().get("osgi.manifest.cache");
bundleManifestLocation = new File(cacheLocation, pluginInfo.getUniqueId() + '_' + pluginInfo.getVersion() + ".MF");
}
try {
fillManifest(compatibilityManifest);
if (upToDate(bundleManifestLocation, pluginManifestLocation))
return bundleManifestLocation;
writeManifest(bundleManifestLocation, generatedManifest, compatibilityManifest);
} catch (PluginConversionException e) {
FrameworkLogEntry entry = new FrameworkLogEntry(PI_ECLIPSE_OSGI, e.getMessage(), 0, e, null);
EclipseAdaptor.getDefault().getFrameworkLog().log(entry);
return null;
};
return bundleManifestLocation;
}
private Set filterExport(Collection exportToFilter, Collection filter) {
if (filter == null || filter.contains("*")) //$NON-NLS-1$
return (Set) exportToFilter;
Set filteredExport = new HashSet(exportToFilter.size());
for (Iterator iter = exportToFilter.iterator(); iter.hasNext(); ) {
String anExport = (String) iter.next();
for (Iterator iter2 = filter.iterator(); iter2.hasNext(); ) {
String aFilter = (String) iter2.next();
if (anExport.startsWith(aFilter)) {
filteredExport.add(anExport);
}
}
}
return filteredExport;
}
private ArrayList findOSJars(File pluginRoot, String path, boolean filter) {
path = path.substring(4);
ArrayList found = new ArrayList(0);
for (int i = 0; i < OS_LIST.length; i++) {
//look for os/osname/path
String searchedPath = "os/" + OS_LIST[i] + "/" + path; //$NON-NLS-1$ //$NON-NLS-2$
if (new File(pluginRoot, searchedPath).exists())
found.add(searchedPath + (filter ? ";(os=" + WS_LIST[i] + ")" : "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
//look for os/osname/archname/path
for (int j = 0; j < ARCH_LIST.length; j++) {
searchedPath = "os/" + OS_LIST[i] + "/" + ARCH_LIST[j] + "/" + path; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (new File(pluginRoot, searchedPath).exists()) {
found.add(searchedPath + (filter ? ";(& (os=" + WS_LIST[i] + ") (arch=" + ARCH_LIST[j] + ")" : "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
}
}
return found;
}
private URL findPluginManifest(File baseLocation) {
//Here, we can not use the bundlefile because it may explode the jar and returns a location from which we will not be able to derive the jars location
URL xmlFileLocation;
InputStream stream = null;
URL baseURL = null;
try {
if (baseLocation.getName().endsWith("jar")) { //$NON-NLS-1$
baseURL = new URL("jar:file:" + baseLocation.toString() + "!/"); //$NON-NLS-1$ //$NON-NLS-2$
} else {
baseURL = baseLocation.toURL();
}
} catch (MalformedURLException e1) {
//this can't happen since we are building the urls ourselves from a file
}
try {
xmlFileLocation = new URL(baseURL, PLUGIN_MANIFEST);
stream = xmlFileLocation.openStream();
return xmlFileLocation;
} catch (MalformedURLException e) {
FrameworkLogEntry entry = new FrameworkLogEntry(EclipseAdaptor.FRAMEWORK_SYMBOLICNAME, e.getMessage(), 0, e.getCause(), null);
EclipseAdaptor.getDefault().getFrameworkLog().log(entry);
return null;
} catch(IOException ioe) {
//ignore
} finally {
try {
if (stream != null)
stream.close();
} catch(IOException e) {
//ignore
}
}
try {
xmlFileLocation = new URL(baseURL, FRAGMENT_MANIFEST);
xmlFileLocation.openStream();
return xmlFileLocation;
} catch (MalformedURLException e) {
FrameworkLogEntry entry = new FrameworkLogEntry(EclipseAdaptor.FRAMEWORK_SYMBOLICNAME, e.getMessage(), 0, e.getCause(), null);
EclipseAdaptor.getDefault().getFrameworkLog().log(entry);
return null;
} catch(IOException ioe) {
// Ignore
} finally {
try {
if (stream != null)
stream.close();
} catch(IOException e) {
//ignore
}
}
return null;
}
private ArrayList findWSJars(File pluginRoot, String path, boolean filter) {
path = path.substring(4);
ArrayList found = new ArrayList(0);
for (int i = 0; i < WS_LIST.length; i++) {
String searchedPath = "ws/" + WS_LIST[i] + path; //$NON-NLS-1$
if (new File(pluginRoot, searchedPath).exists()) {
found.add(searchedPath + (filter ? ";(ws=" + WS_LIST[i] + ")" : "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
return found;
}
protected void fillManifest(boolean compatibilityManifest) {
generateManifestVersion();
generateHeaders();
generateClasspath();
generateActivator();
generatePluginClass();
generateProvidePackage();
generateRequireBundle();
generateLocalizationEntry();
if (compatibilityManifest) {
generateTimestamp();
generateLegacy();
}
}
public void writeManifest(File generationLocation, Dictionary manifestToWrite, boolean compatibilityManifest) throws PluginConversionException {
try {
generationLocation.getParentFile().mkdirs();
generationLocation.createNewFile();
if (!generationLocation.isFile()) {
String message = EclipseAdaptorMsg.formatter.getString("ECLIPSE_CONVERTER_ERROR_CREATING_BUNDLE_MANIFEST",this.pluginInfo.getUniqueId(),generationLocation); //$NON-NLS-1$
throw new PluginConversionException(message);
}
// replaces any eventual existing file
out = new BufferedWriter(new FileWriter(generationLocation));
writeEntry(MANIFEST_VERSION, (String) manifestToWrite.remove(MANIFEST_VERSION));
writeEntry(GENERATED_FROM, (String) manifestToWrite.remove(GENERATED_FROM)); //Need to do this first uptoDate check expect the generated-from tag to be in the first line
Enumeration keys = manifestToWrite.keys();
while (keys.hasMoreElements()) {
String key = (String) keys.nextElement();
writeEntry(key, (String) manifestToWrite.get(key));
}
out.flush();
} catch (IOException e) {
String message = EclipseAdaptorMsg.formatter.getString("ECLIPSE_CONVERTER_ERROR_CREATING_BUNDLE_MANIFEST",this.pluginInfo.getUniqueId(),generationLocation); //$NON-NLS-1$
throw new PluginConversionException(message, e);
} finally {
if (out != null)
try {
out.close();
} catch (IOException e) {
// only report problems writing to/flushing the file
}
}
}
private void generateLocalizationEntry() {
generatedManifest.put(Constants.BUNDLE_MANIFEST_LOCALIZATION, PLUGIN_PROPERTIES_FILENAME);
}
private void generateManifestVersion() {
generatedManifest.put(MANIFEST_VERSION, "1.0"); //$NON-NLS-1$ //$NON-NLS-2$
}
private boolean requireRuntimeCompatibility() {
ArrayList requireList = pluginInfo.getRequires();
for (Iterator iter = requireList.iterator(); iter.hasNext();) {
if (((PluginParser.Prerequisite) iter.next()).getName().equalsIgnoreCase(PI_RUNTIME_COMPATIBILITY))
return true;
}
return false;
}
private void generateActivator() {
if (!pluginInfo.isFragment())
if (! requireRuntimeCompatibility()) {
String pluginClass = pluginInfo.getPluginClass();
if (pluginClass != null)
generatedManifest.put(Constants.BUNDLE_ACTIVATOR, pluginClass);
} else {
generatedManifest.put(Constants.BUNDLE_ACTIVATOR, COMPATIBILITY_ACTIVATOR);
}
}
private void generateClasspath() {
String[] classpath = pluginInfo.getLibrariesName();
if (classpath.length != 0)
generatedManifest.put(Constants.BUNDLE_CLASSPATH, getStringFromArray(classpath,",\n ")); //$NON-NLS-1$
}
private void generateHeaders() {
generatedManifest.put(Constants.BUNDLE_NAME, pluginInfo.getPluginName());
generatedManifest.put(Constants.BUNDLE_VERSION, pluginInfo.getVersion());
generatedManifest.put(Constants.BUNDLE_SYMBOLICNAME, getSymbolicNameEntry(pluginInfo));
String provider = pluginInfo.getProviderName();
if (provider != null)
generatedManifest.put(Constants.BUNDLE_VENDOR, provider);
if (pluginInfo.isFragment()) {
StringBuffer hostBundle = new StringBuffer();
hostBundle.append(pluginInfo.getMasterId()).append("; ");
hostBundle.append(Constants.BUNDLE_VERSION_ATTRIBUTE).append("=");
hostBundle.append(pluginInfo.getMasterVersion());
generatedManifest.put(Constants.FRAGMENT_HOST, hostBundle.toString());
}
}
/*
* Generates an entry in the form:
* <symbolic-name>[; singleton=true]
*/
private String getSymbolicNameEntry(IPluginInfo pluginInfo) {
// false is the default, so don't bother adding anything
if (!pluginInfo.isSingleton())
return pluginInfo.getUniqueId();
StringBuffer result = new StringBuffer(pluginInfo.getUniqueId());
result.append("; "); //$NON-NLS-1$
result.append(Constants.SINGLETON_ATTRIBUTE);
result.append("=true"); //$NON-NLS-1$
return result.toString();
}
private void generateLegacy() {
generatedManifest.put(LEGACY, "true"); //$NON-NLS-1$
}
private void generatePluginClass() {
if (requireRuntimeCompatibility()) {
String pluginClass = pluginInfo.getPluginClass();
if(pluginClass != null)
generatedManifest.put(PLUGIN, pluginClass);
}
}
private void generateProvidePackage() {
Set exports = getExports();
if (exports != null && exports.size() != 0) {
generatedManifest.put(Constants.PROVIDE_PACKAGE, getStringFromCollection(exports,",\n "));
}
}
private void generateRequireBundle() {
ArrayList requiredBundles = pluginInfo.getRequires();
if (requiredBundles.size() == 0)
return;
StringBuffer bundleRequire = new StringBuffer();
for (Iterator iter = requiredBundles.iterator(); iter.hasNext();) {
PluginParser.Prerequisite element = (PluginParser.Prerequisite) iter.next();
StringBuffer modImport = new StringBuffer(element.getName());
if (element.getVersion() != null) {
modImport.append(';').append(Constants.BUNDLE_VERSION_ATTRIBUTE).append("=").append(element.getVersion()); //$NON-NLS-1$
}
if (element.isExported()) {
modImport.append(';').append(Constants.REPROVIDE_ATTRIBUTE).append("=true");//$NON-NLS-1$
}
if (element.isOptional()) {
modImport.append(';').append(Constants.OPTIONAL_ATTRIBUTE).append("=true");//$NON-NLS-1$
}
if (element.getMatch() != null) {
modImport.append(';').append(Constants.VERSION_MATCH_ATTRIBUTE).append("="); //$NON-NLS-1$
if (element.getMatch().equalsIgnoreCase(PLUGIN_REQUIRES_MATCH_PERFECT)) {
modImport.append(Constants.VERSION_MATCH_QUALIFIER);
} else if (element.getMatch().equalsIgnoreCase(PLUGIN_REQUIRES_MATCH_EQUIVALENT)) {
modImport.append(Constants.VERSION_MATCH_MINOR);
} else if (element.getMatch().equalsIgnoreCase(PLUGIN_REQUIRES_MATCH_COMPATIBLE)) {
modImport.append(Constants.VERSION_MATCH_MAJOR);
} else if (element.getMatch().equalsIgnoreCase(PLUGIN_REQUIRES_MATCH_GREATER_OR_EQUAL)) {
modImport.append(Constants.VERSION_MATCH_GREATERTHANOREQUAL);
}
}
bundleRequire.append(modImport);
if (iter.hasNext())
bundleRequire.append(",\n "); //$NON-NLS-1$
}
generatedManifest.put(Constants.REQUIRE_BUNDLE, bundleRequire.toString());
}
private void generateTimestamp() {
// so it is easy to tell which ones are generated
generatedManifest.put(GENERATED_FROM, Long.toString(pluginManifestLocation.lastModified()));
}
private Set getExports() {
Map libs = pluginInfo.getLibraries();
if (libs == null)
return null;
// Based on similar code from EclipseStarter
// Check the osgi.dev property to see if dev classpath entries have been defined.
String[] devClassPath = DevClassPathHelper.getDevClassPath(pluginInfo.getUniqueId());
// add the dev. time classpath entries
List starExport = new ArrayList(1);
starExport.add("*"); //$NON-NLS-1$
if (devClassPath != null) {
for (int i = 0; i < devClassPath.length; i++)
libs.put(devClassPath[i], starExport);
}
Set result = new HashSet(7);
Set libEntries = libs.entrySet();
for (Iterator iter = libEntries.iterator(); iter.hasNext(); ) {
Map.Entry element = (Map.Entry) iter.next();
List filter = (List) element.getValue();
if (filter.size() == 0) //If the library is not exported, then ignore it
continue;
File libraryLocation = new File(pluginManifestLocation, (String) element.getKey());
Set exports = null;
if (libraryLocation.exists()) {
if (libraryLocation.isFile())
exports = filterExport(getExportsFromJAR(libraryLocation), filter); //TODO Need to handle $xx$ variables
else if (libraryLocation.isDirectory())
exports = filterExport(getExportsFromDir(libraryLocation), filter);
} else {
ArrayList expandedLibs = getLibrariesExpandingVariables((String) element.getKey(), false);
exports = new HashSet();
for (Iterator iterator = expandedLibs.iterator(); iterator.hasNext(); ) {
String libName = (String) iterator.next();
File libFile = new File(pluginManifestLocation, libName);
if (libFile.isFile()) {
exports.addAll(filterExport(getExportsFromJAR(libFile), filter));
}
}
}
if (exports != null)
result.addAll(exports);
}
return result;
}
private Set getExportsFromDir(File location) {
return getExportsFromDir(location, ""); //$NON-NLS-1$
}
private Set getExportsFromDir(File location, String packageName) {
String prefix = (packageName.length() > 0) ? (packageName + '.') : ""; //$NON-NLS-1$
File[] files = location.listFiles();
Set exportedPaths = new HashSet();
boolean containsFile = false;
for (int i = 0; i < files.length; i++) {
if (!isValidPackageName(files[i].getName()))
continue;
if (files[i].isDirectory())
exportedPaths.addAll(getExportsFromDir(files[i], prefix + files[i].getName()));
else
containsFile = true;
}
if (containsFile)
// Allow the default package to be provided. If the default package
// contains a File then use "." as the package name to provide for default.
if (packageName.length() > 0)
exportedPaths.add(packageName);
else
exportedPaths.add(".");
return exportedPaths;
}
private Set getExportsFromJAR(File jarFile) {
Set names = new HashSet();
JarFile file = null;
try {
file = new JarFile(jarFile);
} catch (IOException e) {
String message = EclipseAdaptorMsg.formatter.getString("ECLIPSE_CONVERTER_PLUGIN_LIBRARY_IGNORED", jarFile, pluginInfo.getUniqueId());
EclipseAdaptor.getDefault().getFrameworkLog().log(new FrameworkLogEntry(PI_ECLIPSE_OSGI, message, 0, e, null));
return names;
}
//Run through the entries
for (Enumeration enum = file.entries(); enum.hasMoreElements(); ) {
JarEntry entry = (JarEntry) enum.nextElement();
String name = entry.getName();
if (!isValidPackageName(name))
continue;
int lastSlash = name.lastIndexOf("/"); //$NON-NLS-1$
//Ignore folders that do not contain files
if (lastSlash != -1) {
if (lastSlash != name.length() - 1 && name.lastIndexOf(' ') == -1)
names.add(name.substring(0, lastSlash).replace('/', '.'));
}
else {
// Allow the default package to be provided. If the default package
// contains a File then use "." as the package name to provide for default.
names.add(".");
}
}
return names;
}
private ArrayList getLibrariesExpandingVariables(String libraryPath, boolean filter) {
String var = hasPrefix(libraryPath);
if (var == null) {
ArrayList returnValue = new ArrayList(1);
returnValue.add(libraryPath);
return returnValue;
}
if (var.equals("ws")) { //$NON-NLS-1$
return findWSJars(pluginManifestLocation.getParentFile(), libraryPath, filter);
}
if (var.equals("os")) { //$NON-NLS-1$
return findOSJars(pluginManifestLocation, libraryPath, filter);
}
return new ArrayList(0);
}
//return a String representing the string found between the $s
private String hasPrefix(String libPath) {
if (libPath.startsWith("$ws$")) //$NON-NLS-1$
return "ws"; //$NON-NLS-1$
if (libPath.startsWith("$os$")) //$NON-NLS-1$
return "os"; //$NON-NLS-1$
if (libPath.startsWith("$nl$")) //$NON-NLS-1$
return "nl"; //$NON-NLS-1$
return null;
}
private boolean isValidPackageName(String name) {
if (name.indexOf(' ') > 0 || name.equalsIgnoreCase("META-INF") || name.startsWith("META-INF/")) //$NON-NLS-1$ //$NON-NLS-2$
return false;
return true;
}
/**
* Parses the plugin manifest to find out: - the plug-in unique identifier -
* the plug-in version - runtime/libraries entries - the plug-in class -
* the master plugin (for a fragment)
*/
private IPluginInfo parsePluginInfo(URL pluginLocation) throws PluginConversionException {
InputStream input = null;
try {
input = new BufferedInputStream(pluginLocation.openStream());
return new PluginParser(context).parsePlugin(input);
} catch (Exception e) {
String message = EclipseAdaptorMsg.formatter.getString("ECLIPSE_CONVERTER_ERROR_PARSING_PLUGIN_MANIFEST", pluginManifestLocation); //$NON-NLS-1$
throw new PluginConversionException(message, e);
} finally {
if (input!=null)
try {
input.close();
} catch(IOException e) {
//ignore exception
}
}
}
public static boolean upToDate(File generationLocation, File pluginLocation) {
if (!generationLocation.isFile())
return false;
String secondLine = null;
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(generationLocation)));
reader.readLine();
secondLine = reader.readLine();
} catch (IOException e) {
// not a big deal - we could not read an existing manifest
return false;
} finally {
if (reader != null)
try {
reader.close();
} catch (IOException e) {
// ignore
}
}
String tag = GENERATED_FROM + ": "; //$NON-NLS-1$
if (secondLine == null || !secondLine.startsWith(tag))
return false;
String timestampStr = secondLine.substring(tag.length() - 1);
try {
return Long.parseLong(timestampStr.trim()) == pluginLocation.lastModified();
} catch(NumberFormatException nfe) {
// not a big deal - just a bogus existing manifest that will be ignored
}
return false;
}
private void writeEntry(String key, String value) throws IOException {
if (value != null && value.length() > 0) {
out.write(key + ": " + value); //$NON-NLS-1$
out.newLine();
}
}
private void writeEntry(String key, String[] value) throws IOException {
if (value == null || value.length == 0)
return;
if (value.length == 1) {
out.write(key + ": " + value[0]); //$NON-NLS-1$
out.newLine();
return;
}
key = key + ": "; //$NON-NLS-1$
out.write(key);
out.newLine();
out.write(' ');
boolean first = true;
for (int i = 0; i < value.length; i++) {
if (first)
first = false;
else {
out.write(',');
out.newLine();
out.write(' ');
}
out.write(value[i]);
}
out.newLine();
}
private String getStringFromArray(String[] values, String separator) {
if (values==null)
return "";
StringBuffer result = new StringBuffer();
for (int i = 0; i < values.length; i++) {
if (i > 0)
result.append(separator);
result.append(values[i]);
}
return result.toString();
}
private String getStringFromCollection(Collection collection, String separator) {
StringBuffer result = new StringBuffer();
boolean first = true;
for (Iterator i = collection.iterator(); i.hasNext();) {
if (first)
first = false;
else
result.append(separator);
result.append(i.next());
}
return result.toString();
}
public class PluginConversionException extends Exception {
public PluginConversionException() {
super();
}
public PluginConversionException(String message) {
super(message);
}
public PluginConversionException(String message, Throwable cause) {
super(message, cause);
}
public PluginConversionException(Throwable cause) {
super(cause);
}
}
public Dictionary convertManifest(File pluginBaseLocation, boolean compatibility) {
init();
fillPluginInfo(pluginBaseLocation);
if (pluginInfo==null)
return null;
fillManifest(compatibility);
return generatedManifest;
}
}