com.siteview.mde.internal.core.converter.MonitorConverter.java Source code

Java tutorial

Introduction

Here is the source code for com.siteview.mde.internal.core.converter.MonitorConverter.java

Source

/*******************************************************************************
 *  Copyright (c) 2003, 2010 IBM Corporation and others.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  which accompanies this distribution, and is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 * 
 *  Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package com.siteview.mde.internal.core.converter;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import org.eclipse.core.resources.*;
import org.eclipse.jdt.core.*;
import org.eclipse.osgi.service.pluginconversion.PluginConversionException;
import org.eclipse.osgi.service.resolver.VersionRange;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.osgi.util.NLS;
import com.siteview.mde.core.build.IBuild;
import com.siteview.mde.core.build.IBuildEntry;
import com.siteview.mde.internal.core.*;
import com.siteview.mde.internal.core.build.Build;
import com.siteview.mde.internal.core.build.WorkspaceBuildModel;
import com.siteview.mde.internal.core.converter.MonitorConverterParser.PluginInfo;
import com.siteview.mde.internal.core.project.PDEProject;
import org.osgi.framework.*;

public class MonitorConverter {
    public static boolean DEBUG = false;
    /** bundle manifest type unknown */
    static public final byte MANIFEST_TYPE_UNKNOWN = 0x00;
    /** bundle manifest type bundle (META-INF/MANIFEST.MF) */
    static public final byte MANIFEST_TYPE_BUNDLE = 0x01;
    /** bundle manifest type plugin (plugin.xml) */
    static public final byte MANIFEST_TYPE_PLUGIN = 0x02;
    /** bundle manifest type fragment (fragment.xml) */
    static public final byte MANIFEST_TYPE_FRAGMENT = 0x04;
    /** bundle manifest type jared bundle */
    static public final byte MANIFEST_TYPE_JAR = 0x08;

    private static final String SEMICOLON = "; "; //$NON-NLS-1$
    private static final String UTF_8 = "UTF-8"; //$NON-NLS-1$
    public static final String LIST_SEPARATOR = ",\n "; //$NON-NLS-1$
    public static final String LINE_SEPARATOR = "\n "; //$NON-NLS-1$
    private static int MAXLINE = 511;
    private BundleContext context;
    private PluginInfo pluginInfo;
    private File pluginManifestLocation;
    private Dictionary generatedManifest;
    private byte manifestType;
    private Version target;
    static final Version TARGET31 = new Version(3, 1, 0);
    static final Version TARGET32 = new Version(3, 2, 0);
    static final Version TARGET34 = new Version(3, 4, 0);
    private static final String MANIFEST_VERSION = "Manifest-Version"; //$NON-NLS-1$
    private static final String PLUGIN_PROPERTIES_FILENAME = "plugin"; //$NON-NLS-1$
    private static MonitorConverter instance;
    static public final String GENERATED_FROM = "Generated-from"; //$NON-NLS-1$
    static public final String MANIFEST_TYPE_ATTRIBUTE = "type"; //$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 COMPATIBILITY_ACTIVATOR = "org.eclipse.core.internal.compatibility.PluginActivator"; //$NON-NLS-1$
    private static final String SOURCE_PREFIX = "source."; //$NON-NLS-1$

    public static MonitorConverter getDefault() {
        if (instance == null)
            instance = new MonitorConverter(MDECore.getDefault().getBundleContext());
        return instance;
    }

    public MonitorConverter(BundleContext context) {
        this.context = context;
        instance = this;
    }

    private void init() {
        // need to make sure these fields are cleared out for each conversion.
        pluginInfo = null;
        pluginManifestLocation = null;
        generatedManifest = new Hashtable(10);
        manifestType = MANIFEST_TYPE_UNKNOWN;
        target = null;
    }

    private void fillPluginInfo(File pluginBaseLocation) throws PluginConversionException {
        pluginManifestLocation = pluginBaseLocation;
        if (pluginManifestLocation == null)
            throw new IllegalArgumentException();
        URL pluginFile = findPluginManifest(pluginBaseLocation);
        if (pluginFile == null) {
            throw new PluginConversionException(
                    NLS.bind(MDECoreMessages.PluginConverter_EclipseConverterFileNotFound,
                            pluginBaseLocation.getAbsolutePath()));
        }
        pluginInfo = parsePluginInfo(pluginFile);
        String validation = pluginInfo.validateForm();
        if (validation != null)
            throw new PluginConversionException(validation);
    }

    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.isDirectory()) {
                baseURL = new URL("jar:file:" + baseLocation.toString() + "!/"); //$NON-NLS-1$ //$NON-NLS-2$
                manifestType |= MANIFEST_TYPE_JAR;
            } 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, ICoreConstants.PLUGIN_FILENAME_DESCRIPTOR);
            stream = xmlFileLocation.openStream();
            manifestType |= MANIFEST_TYPE_PLUGIN;
            return xmlFileLocation;
        } catch (MalformedURLException e) {
            return null;
        } catch (IOException ioe) {
            //ignore
        } finally {
            try {
                if (stream != null)
                    stream.close();
            } catch (IOException e) {
                //ignore
            }
        }
        try {
            xmlFileLocation = new URL(baseURL, ICoreConstants.FRAGMENT_FILENAME_DESCRIPTOR);
            stream = xmlFileLocation.openStream();
            manifestType |= MANIFEST_TYPE_FRAGMENT;
            return xmlFileLocation;
        } catch (MalformedURLException e) {
            return null;
        } catch (IOException ioe) {
            // Ignore
        } finally {
            try {
                if (stream != null)
                    stream.close();
            } catch (IOException e) {
                //ignore
            }
        }
        return null;
    }

    protected void fillManifest(boolean compatibilityManifest, boolean analyseJars) {
        generateManifestVersion();
        generateHeaders();
        generateClasspath();
        generateActivator();
        generatePluginClass();
        if (analyseJars)
            generateProvidePackage();
        generateRequireBundle();
        generateLocalizationEntry();
        generateEclipseHeaders();
        if (compatibilityManifest) {
            generateTimestamp();
        }
    }

    public void writeManifest(File generationLocation, Map manifestToWrite, boolean compatibilityManifest)
            throws PluginConversionException {
        long start = System.currentTimeMillis();
        BufferedWriter out = null;
        try {
            File parentFile = new File(generationLocation.getParent());
            parentFile.mkdirs();
            generationLocation.createNewFile();
            if (!generationLocation.isFile()) {
                String message = NLS.bind(
                        MDECoreMessages.PluginConverter_EclipseConverterErrorCreatingBundleManifest,
                        this.pluginInfo.getUniqueId(), generationLocation);
                throw new PluginConversionException(message);
            }
            // MANIFEST.MF files must be written using UTF-8
            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(generationLocation), UTF_8));
            writeManifest(manifestToWrite, out);
        } catch (IOException e) {
            String message = NLS.bind(MDECoreMessages.PluginConverter_EclipseConverterErrorCreatingBundleManifest,
                    this.pluginInfo.getUniqueId(), generationLocation);
            throw new PluginConversionException(message, e);
        } finally {
            if (out != null)
                try {
                    out.close();
                } catch (IOException e) {
                    // only report problems writing to/flushing the file
                }
        }
        if (DEBUG)
            System.out.println("Time to write out converted manifest to: " + generationLocation + ": " //$NON-NLS-1$//$NON-NLS-2$
                    + (System.currentTimeMillis() - start) + "ms."); //$NON-NLS-1$
    }

    public void writeManifest(Map manifestToWrite, Writer out) throws IOException {
        // replaces any eventual existing file
        manifestToWrite = new Hashtable(manifestToWrite);

        writeEntry(out, MANIFEST_VERSION, (String) manifestToWrite.remove(MANIFEST_VERSION));
        writeEntry(out, 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
        // always attempt to write the Bundle-ManifestVersion header if it exists (bug 109863)
        writeEntry(out, Constants.BUNDLE_MANIFESTVERSION,
                (String) manifestToWrite.remove(Constants.BUNDLE_MANIFESTVERSION));
        writeEntry(out, Constants.BUNDLE_NAME, (String) manifestToWrite.remove(Constants.BUNDLE_NAME));
        writeEntry(out, Constants.BUNDLE_SYMBOLICNAME,
                (String) manifestToWrite.remove(Constants.BUNDLE_SYMBOLICNAME));
        writeEntry(out, Constants.BUNDLE_VERSION, (String) manifestToWrite.remove(Constants.BUNDLE_VERSION));
        writeEntry(out, Constants.BUNDLE_CLASSPATH, (String) manifestToWrite.remove(Constants.BUNDLE_CLASSPATH));
        writeEntry(out, Constants.BUNDLE_ACTIVATOR, (String) manifestToWrite.remove(Constants.BUNDLE_ACTIVATOR));
        writeEntry(out, Constants.BUNDLE_VENDOR, (String) manifestToWrite.remove(Constants.BUNDLE_VENDOR));
        writeEntry(out, Constants.FRAGMENT_HOST, (String) manifestToWrite.remove(Constants.FRAGMENT_HOST));
        writeEntry(out, Constants.BUNDLE_LOCALIZATION,
                (String) manifestToWrite.remove(Constants.BUNDLE_LOCALIZATION));
        // always attempt to write the Export-Package header if it exists (bug 109863)
        writeEntry(out, Constants.EXPORT_PACKAGE, (String) manifestToWrite.remove(Constants.EXPORT_PACKAGE));
        // always attempt to write the Provide-Package header if it exists (bug 109863)
        writeEntry(out, ICoreConstants.PROVIDE_PACKAGE,
                (String) manifestToWrite.remove(ICoreConstants.PROVIDE_PACKAGE));
        writeEntry(out, Constants.REQUIRE_BUNDLE, (String) manifestToWrite.remove(Constants.REQUIRE_BUNDLE));
        Iterator keys = manifestToWrite.keySet().iterator();
        // TODO makes sure the update works from Dictionary
        while (keys.hasNext()) {
            String key = (String) keys.next();
            writeEntry(out, key, (String) manifestToWrite.get(key));
        }
        out.flush();
    }

    private void generateLocalizationEntry() {
        generatedManifest.put(Constants.BUNDLE_LOCALIZATION, PLUGIN_PROPERTIES_FILENAME);
    }

    private void generateManifestVersion() {
        generatedManifest.put(MANIFEST_VERSION, "1.0"); //$NON-NLS-1$ 
    }

    private boolean requireRuntimeCompatibility() {
        ArrayList requireList = pluginInfo.getRequires();
        for (Iterator iter = requireList.iterator(); iter.hasNext();) {
            if (((MonitorConverterParser.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 && !pluginClass.trim().equals("")) //$NON-NLS-1$
                    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, LIST_SEPARATOR));
    }

    private void generateHeaders() {
        if (TARGET31.compareTo(target) <= 0)
            generatedManifest.put(Constants.BUNDLE_MANIFESTVERSION, "2"); //$NON-NLS-1$
        generatedManifest.put(Constants.BUNDLE_NAME, pluginInfo.getPluginName());
        generatedManifest.put(Constants.BUNDLE_VERSION, pluginInfo.getVersion());
        generatedManifest.put(Constants.BUNDLE_SYMBOLICNAME, getSymbolicNameEntry());
        String provider = pluginInfo.getProviderName();
        if (provider != null)
            generatedManifest.put(Constants.BUNDLE_VENDOR, provider);
        if (pluginInfo.isFragment()) {
            StringBuffer hostBundle = new StringBuffer();
            hostBundle.append(pluginInfo.getMasterId());
            String versionRange = getVersionRange(pluginInfo.getMasterVersion(), pluginInfo.getMasterMatch()); // TODO need to get match rule here!
            if (versionRange != null)
                hostBundle.append(versionRange);
            generatedManifest.put(Constants.FRAGMENT_HOST, hostBundle.toString());
        }
    }

    /*
     * Generates an entry in the form: 
     *    <symbolic-name>[; singleton=true]
     */
    private String getSymbolicNameEntry() {
        // false is the default, so don't bother adding anything 
        if (!pluginInfo.isSingleton())
            return pluginInfo.getUniqueId();
        StringBuffer result = new StringBuffer(pluginInfo.getUniqueId());
        result.append(SEMICOLON);
        result.append(Constants.SINGLETON_DIRECTIVE);
        String assignment = TARGET31.compareTo(target) <= 0 ? ":=" : "="; //$NON-NLS-1$ //$NON-NLS-2$
        result.append(assignment).append("true"); //$NON-NLS-1$
        return result.toString();
    }

    private void generatePluginClass() {
        if (requireRuntimeCompatibility()) {
            String pluginClass = pluginInfo.getPluginClass();
            if (pluginClass != null)
                generatedManifest.put(ICoreConstants.PLUGIN_CLASS, pluginClass);
        }
    }

    private void generateProvidePackage() {
        Collection exports = getExports();
        if (exports != null && exports.size() != 0) {
            generatedManifest.put(
                    TARGET31.compareTo(target) <= 0 ? Constants.EXPORT_PACKAGE : ICoreConstants.PROVIDE_PACKAGE,
                    getStringFromCollection(exports, LIST_SEPARATOR));
        }
    }

    private void generateRequireBundle() {
        ArrayList requiredBundles = pluginInfo.getRequires();
        if (requiredBundles.size() == 0)
            return;
        StringBuffer bundleRequire = new StringBuffer();
        for (Iterator iter = requiredBundles.iterator(); iter.hasNext();) {
            MonitorConverterParser.Prerequisite element = (MonitorConverterParser.Prerequisite) iter.next();
            StringBuffer modImport = new StringBuffer(element.getName());
            String versionRange = getVersionRange(element.getVersion(), element.getMatch());
            if (versionRange != null)
                modImport.append(versionRange);
            if (element.isExported()) {
                if (TARGET31.compareTo(target) <= 0)
                    modImport.append(';').append(Constants.VISIBILITY_DIRECTIVE).append(":=") //$NON-NLS-1$
                            .append(Constants.VISIBILITY_REEXPORT);
                else
                    modImport.append(';').append(ICoreConstants.REPROVIDE_ATTRIBUTE).append("=true");//$NON-NLS-1$
            }
            if (element.isOptional()) {
                if (TARGET31.compareTo(target) <= 0)
                    modImport.append(';').append(Constants.RESOLUTION_DIRECTIVE).append(":=") //$NON-NLS-1$
                            .append(Constants.RESOLUTION_OPTIONAL);
                else
                    modImport.append(';').append(ICoreConstants.OPTIONAL_ATTRIBUTE).append("=true");//$NON-NLS-1$
            }
            bundleRequire.append(modImport.toString());
            if (iter.hasNext())
                bundleRequire.append(LIST_SEPARATOR);
        }
        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(getTimeStamp(pluginManifestLocation, manifestType))
                + ";" + MANIFEST_TYPE_ATTRIBUTE + "=" + manifestType); //$NON-NLS-1$ //$NON-NLS-2$
    }

    private void generateEclipseHeaders() {
        if (pluginInfo.isFragment())
            return;

        String pluginClass = pluginInfo.getPluginClass();
        if (pluginInfo.hasExtensionExtensionPoints() || (pluginClass != null && !pluginClass.trim().equals(""))) { //$NON-NLS-1$
            if (TARGET34.compareTo(target) <= 0)
                generatedManifest.put(Constants.BUNDLE_ACTIVATIONPOLICY, Constants.ACTIVATION_LAZY);
            else
                generatedManifest.put(TARGET32.compareTo(target) <= 0 ? ICoreConstants.ECLIPSE_LAZYSTART
                        : ICoreConstants.ECLIPSE_AUTOSTART, "true"); //$NON-NLS-1$
        }
    }

    private Set getExports() {
        Map libs = pluginInfo.getLibraries();
        if (libs == null)
            return null;

        String projName = pluginManifestLocation.getName();
        IProject proj = ResourcesPlugin.getWorkspace().getRoot().getProject(projName);
        if (proj == null)
            return null;

        return getExports(proj, libs);
    }

    public Set getExports(IProject proj, Map libs) {
        IFile buildProperties = PDEProject.getBuildProperties(proj);
        IBuild build = null;
        if (buildProperties != null) {
            WorkspaceBuildModel buildModel = new WorkspaceBuildModel(buildProperties);
            build = buildModel.getBuild();
        } else
            build = new Build();
        return findPackages(proj, libs, build);
    }

    private Set findPackages(IProject proj, Map libs, IBuild build) {
        TreeSet result = new TreeSet();
        IJavaProject jp = JavaCore.create(proj);
        Iterator it = libs.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String libName = entry.getKey().toString();
            List filter = (List) entry.getValue();
            IBuildEntry libEntry = build.getEntry(SOURCE_PREFIX + libName);
            if (libEntry != null) {
                String[] tokens = libEntry.getTokens();
                for (int i = 0; i < tokens.length; i++) {
                    IResource folder = null;
                    if (tokens[i].equals(".")) //$NON-NLS-1$
                        folder = proj;
                    else
                        folder = proj.getFolder(tokens[i]);
                    if (folder != null)
                        addPackagesFromFragRoot(jp.getPackageFragmentRoot(folder), result, filter);
                }
            } else {
                IResource res = proj.findMember(libName);
                if (res != null)
                    addPackagesFromFragRoot(jp.getPackageFragmentRoot(res), result, filter);
            }
        }
        return result;
    }

    private void addPackagesFromFragRoot(IPackageFragmentRoot root, Collection result, List filter) {
        if (root == null)
            return;
        try {
            if (filter != null && !filter.contains("*")) { //$NON-NLS-1$
                ListIterator li = filter.listIterator();
                while (li.hasNext()) {
                    String pkgName = li.next().toString();
                    if (pkgName.endsWith(".*")) //$NON-NLS-1$
                        pkgName = pkgName.substring(0, pkgName.length() - 2);

                    IPackageFragment frag = root.getPackageFragment(pkgName);
                    if (frag != null)
                        result.add(pkgName);
                }
                return;
            }
            IJavaElement[] children = root.getChildren();
            for (int j = 0; j < children.length; j++) {
                IPackageFragment fragment = (IPackageFragment) children[j];
                String name = fragment.getElementName();
                if (fragment.hasChildren() && !result.contains(name)) {
                    result.add(name);
                }
            }
        } catch (JavaModelException e) {
        }
    }

    /**
     * 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 PluginInfo parsePluginInfo(URL pluginLocation) throws PluginConversionException {
        InputStream input = null;
        try {
            input = new BufferedInputStream(pluginLocation.openStream());
            return new MonitorConverterParser(context, target).parsePlugin(input);
        } catch (Exception e) {
            String message = NLS.bind(MDECoreMessages.PluginConverter_EclipseConverterErrorParsingPluginManifest,
                    pluginManifestLocation);
            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, byte manifestType) {
        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;

        secondLine = secondLine.substring(tag.length());
        ManifestElement generatedFrom;
        try {
            generatedFrom = ManifestElement.parseHeader(MonitorConverter.GENERATED_FROM, secondLine)[0];
        } catch (BundleException be) {
            return false;
        }
        String timestampStr = generatedFrom.getValue();
        try {
            return Long.parseLong(timestampStr.trim()) == getTimeStamp(pluginLocation, manifestType);
        } catch (NumberFormatException nfe) {
            // not a big deal - just a bogus existing manifest that will be ignored
        }
        return false;
    }

    public static long getTimeStamp(File pluginLocation, byte manifestType) {
        if ((manifestType & MANIFEST_TYPE_JAR) != 0)
            return pluginLocation.lastModified();
        else if ((manifestType & MANIFEST_TYPE_PLUGIN) != 0)
            return new File(pluginLocation, ICoreConstants.PLUGIN_FILENAME_DESCRIPTOR).lastModified();
        else if ((manifestType & MANIFEST_TYPE_FRAGMENT) != 0)
            return new File(pluginLocation, ICoreConstants.FRAGMENT_FILENAME_DESCRIPTOR).lastModified();
        else if ((manifestType & MANIFEST_TYPE_BUNDLE) != 0)
            return new File(pluginLocation, ICoreConstants.BUNDLE_FILENAME_DESCRIPTOR).lastModified();
        return -1;
    }

    private void writeEntry(Writer out, String key, String value) throws IOException {
        if (value != null && value.length() > 0) {
            out.write(splitOnComma(key + ": " + value)); //$NON-NLS-1$
            out.write('\n');
        }
    }

    private String splitOnComma(String value) {
        if (value.length() < MAXLINE || value.indexOf(LINE_SEPARATOR) >= 0)
            return value; // assume the line is already split
        String[] values = ManifestElement.getArrayFromList(value);
        if (values == null || values.length == 0)
            return value;
        StringBuffer sb = new StringBuffer(value.length() + ((values.length - 1) * LIST_SEPARATOR.length()));
        for (int i = 0; i < values.length - 1; i++)
            sb.append(values[i]).append(LIST_SEPARATOR);
        sb.append(values[values.length - 1]);
        return sb.toString();
    }

    private String getStringFromArray(String[] values, String separator) {
        if (values == null)
            return ""; //$NON-NLS-1$
        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 synchronized Dictionary convertManifest(File pluginBaseLocation, boolean compatibility, String target,
            boolean analyseJars, Dictionary devProperties) throws PluginConversionException {
        long start = System.currentTimeMillis();
        if (DEBUG)
            System.out.println("Convert " + pluginBaseLocation); //$NON-NLS-1$
        init();
        this.target = target == null ? TARGET32 : new Version(target);
        fillPluginInfo(pluginBaseLocation);
        fillManifest(compatibility, analyseJars);
        if (DEBUG)
            System.out.println("Time to convert manifest for: " + pluginBaseLocation + ": " //$NON-NLS-1$//$NON-NLS-2$
                    + (System.currentTimeMillis() - start) + "ms."); //$NON-NLS-1$
        return generatedManifest;
    }

    public synchronized File convertManifest(File pluginBaseLocation, File bundleManifestLocation,
            boolean compatibilityManifest, String target, boolean analyseJars, Dictionary devProperties)
            throws PluginConversionException {
        if (bundleManifestLocation == null)
            throw new PluginConversionException(MDECoreMessages.PluginConverter_BundleLocationIsNull);
        convertManifest(pluginBaseLocation, compatibilityManifest, target, analyseJars, devProperties);
        if (upToDate(bundleManifestLocation, pluginManifestLocation, manifestType))
            return bundleManifestLocation;
        writeManifest(bundleManifestLocation, (Map) generatedManifest, compatibilityManifest);
        return bundleManifestLocation;
    }

    private String getVersionRange(String reqVersion, String matchRule) {
        if (reqVersion == null)
            return null;

        Version minVersion = Version.parseVersion(reqVersion);
        String versionRange;
        if (matchRule != null) {
            if (matchRule.equalsIgnoreCase(IModel.PLUGIN_REQUIRES_MATCH_PERFECT)) {
                versionRange = new VersionRange(minVersion, true, minVersion, true).toString();
            } else if (matchRule.equalsIgnoreCase(IModel.PLUGIN_REQUIRES_MATCH_EQUIVALENT)) {
                versionRange = new VersionRange(minVersion, true,
                        new Version(minVersion.getMajor(), minVersion.getMinor() + 1, 0, ""), false).toString(); //$NON-NLS-1$
            } else if (matchRule.equalsIgnoreCase(IModel.PLUGIN_REQUIRES_MATCH_COMPATIBLE)) {
                versionRange = new VersionRange(minVersion, true, new Version(minVersion.getMajor() + 1, 0, 0, ""), //$NON-NLS-1$
                        false).toString();
            } else if (matchRule.equalsIgnoreCase(IModel.PLUGIN_REQUIRES_MATCH_GREATER_OR_EQUAL)) {
                // just return the reqVersion here without any version range
                versionRange = reqVersion;
            } else {
                versionRange = new VersionRange(minVersion, true, new Version(minVersion.getMajor() + 1, 0, 0, ""), //$NON-NLS-1$
                        false).toString();
            }
        } else {
            versionRange = new VersionRange(minVersion, true, new Version(minVersion.getMajor() + 1, 0, 0, ""), //$NON-NLS-1$
                    false).toString();
        }

        StringBuffer result = new StringBuffer();
        result.append(';').append(Constants.BUNDLE_VERSION_ATTRIBUTE).append('=');
        result.append('\"').append(versionRange).append('\"');
        return result.toString();
    }
}