Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools')
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Entries2
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Repository1
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Root1
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Tag1
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Entries1
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Repository1
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Root1
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Tag1
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/Activator.java101
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Entries21
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Repository1
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Root1
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Tag1
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CheckedItem.java109
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/ClassFileHelper.java93
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CompareOptionFileHelper.java390
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CompareResult.java49
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/FeatureModelTable.java386
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/FeatureVersionCompare.java811
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/JavaClassVersionCompare.java654
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/ManifestHelper.java149
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/Messages.java122
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/PluginVersionCompare.java889
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionClassDirFilter.java63
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionCompareConstants.java68
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionCompareDispatcher.java322
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionVerifier.java223
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningDirFilter.java60
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningFeatureFileFilter.java53
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningFilenameFilter.java46
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningProgressMonitorWrapper.java63
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/messages.properties102
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Entries4
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Repository1
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Root1
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Tag1
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/ICompareResult.java59
-rw-r--r--FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/IVersionCompare.java547
-rwxr-xr-xFROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/VersionCompareFactory.java39
39 files changed, 5438 insertions, 0 deletions
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Entries b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Entries
new file mode 100644
index 000000000..399714e97
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Entries
@@ -0,0 +1,2 @@
+D/internal////
+D/versioning////
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Repository b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Repository
new file mode 100644
index 000000000..e5e983673
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Repository
@@ -0,0 +1 @@
+org.eclipse.sdk.tests-feature/plugins/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Root b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Root
new file mode 100644
index 000000000..2d37d165b
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Root
@@ -0,0 +1 @@
+:pserver:anonymous@dev.eclipse.org:/cvsroot/eclipse
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Tag b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Tag
new file mode 100644
index 000000000..4dc597cc4
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/CVS/Tag
@@ -0,0 +1 @@
+Tr20080922
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Entries b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Entries
new file mode 100644
index 000000000..6a61f3c67
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Entries
@@ -0,0 +1 @@
+D/versioning////
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Repository b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Repository
new file mode 100644
index 000000000..07366a6a4
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Repository
@@ -0,0 +1 @@
+org.eclipse.sdk.tests-feature/plugins/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Root b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Root
new file mode 100644
index 000000000..2d37d165b
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Root
@@ -0,0 +1 @@
+:pserver:anonymous@dev.eclipse.org:/cvsroot/eclipse
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Tag b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Tag
new file mode 100644
index 000000000..4dc597cc4
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/CVS/Tag
@@ -0,0 +1 @@
+Tr20080922
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/Activator.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/Activator.java
new file mode 100755
index 000000000..5983ccade
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/Activator.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import org.eclipse.osgi.service.debug.DebugOptions;
+import org.eclipse.osgi.service.pluginconversion.PluginConverter;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * org.eclipse.pde.tools.versioning bundle activator
+ *
+ */
+public class Activator implements BundleActivator {
+ public static final String PLUGIN_ID = "org.eclipse.pde.tools.versioning"; //$NON-NLS-1$
+ private static PluginConverter pluginConverter = null;
+ private static BundleContext context = null;
+ private static ServiceTracker bundleTracker = null;
+ private static ServiceTracker debugTracker = null;
+
+ /**
+ * Log the given debug message.
+ */
+ public static void debug(String message) {
+ if (message != null)
+ System.out.println(message);
+ }
+
+ /**
+ * Return a boolean value indicating whether or not debug options are
+ * turned on for the given key.
+ */
+ public static boolean getBooleanDebugOption(String key) {
+ if (context == null)
+ return false;
+ if (debugTracker == null) {
+ debugTracker = new ServiceTracker(context, DebugOptions.class.getName(), null);
+ debugTracker.open();
+ }
+ DebugOptions debug = (DebugOptions) debugTracker.getService();
+ return debug == null ? false : debug.getBooleanOption(key, false);
+ }
+
+ /*
+ * Constructor for the class.
+ */
+ public Activator() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext runtimeContext) throws Exception {
+ context = runtimeContext;
+ }
+
+ /* (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext runtimeContext) {
+ if (bundleTracker != null) {
+ bundleTracker.close();
+ bundleTracker = null;
+ }
+ if (debugTracker != null) {
+ debugTracker.close();
+ debugTracker = null;
+ }
+ context = null;
+ pluginConverter = null;
+ }
+
+ /**
+ * Return the plug-in converter class or <code>null</code> if it
+ * is not available.
+ *
+ * @return the plug-in converter or <code>null</code>
+ */
+ public static PluginConverter getPluginConverter() {
+ if (pluginConverter == null) {
+ if (bundleTracker == null) {
+ if (context == null)
+ return null;
+ bundleTracker = new ServiceTracker(context, PluginConverter.class.getName(), null);
+ bundleTracker.open();
+ }
+ pluginConverter = (PluginConverter) bundleTracker.getService();
+ }
+ return pluginConverter;
+ }
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Entries b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Entries
new file mode 100644
index 000000000..8c69857b6
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Entries
@@ -0,0 +1,21 @@
+/Activator.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/CheckedItem.java/1.2/Tue Oct 10 15:43:45 2006//Tr20080922
+/ClassFileHelper.java/1.2/Tue Oct 10 15:43:45 2006//Tr20080922
+/CompareOptionFileHelper.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/CompareResult.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/FeatureModelTable.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/FeatureVersionCompare.java/1.2/Mon Sep 22 17:32:07 2008//Tr20080922
+/JavaClassVersionCompare.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/ManifestHelper.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/Messages.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/PluginVersionCompare.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/VersionClassDirFilter.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/VersionCompareConstants.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/VersionCompareDispatcher.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/VersionVerifier.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/VersioningDirFilter.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/VersioningFeatureFileFilter.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/VersioningFilenameFilter.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/VersioningProgressMonitorWrapper.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/messages.properties/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+D
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Repository b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Repository
new file mode 100644
index 000000000..34c27aef8
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Repository
@@ -0,0 +1 @@
+org.eclipse.sdk.tests-feature/plugins/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Root b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Root
new file mode 100644
index 000000000..2d37d165b
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Root
@@ -0,0 +1 @@
+:pserver:anonymous@dev.eclipse.org:/cvsroot/eclipse
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Tag b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Tag
new file mode 100644
index 000000000..25d2caaa5
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CVS/Tag
@@ -0,0 +1 @@
+Nr20080922
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CheckedItem.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CheckedItem.java
new file mode 100755
index 000000000..66f6a5045
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CheckedItem.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import org.eclipse.pde.tools.versioning.IVersionCompare;
+import org.osgi.framework.Version;
+
+/**
+ * This class represents version change of a checked feature(or plugin)
+ */
+public class CheckedItem {
+ /**
+ * compare source feature or plugin key(id + "#" + version)
+ */
+ private String sourceKey;
+ /**
+ * compare destination feature or plugin key(id + "#" + version)
+ * for plugin, this value must be set when create a new instance of this class,
+ * since it is possible there are two plugins have the same id but different versions exist
+ * in an Eclipse installation;
+ * for feature, this value can be set as <code>null</code>
+ */
+ private String destinationKey;
+ private Version version;
+ private int change;
+
+ /**
+ * Constructor for the class. Set the key, version, and change to be the given values.
+ *
+ * @param sourceKey compare source feature id(or plugin id) + "#" + feature version(or plugin version)
+ * @param destinationKey compare destination feature id(or plugin id) + "#" + feature version(or plugin version)
+ * @param version if the new version is correct, it is the new version; if the new version
+ * is incorrect, it is the recommended version; if some error happened, it is <code>null</code>
+ * @param change change happened on the feature or plugin
+ */
+ public CheckedItem(String sourceKey, String destinationKey, Version version, int change) {
+ this.sourceKey = sourceKey;
+ this.destinationKey = destinationKey;
+ this.version = version;
+ this.change = change;
+ }
+
+ /**
+ * Return the compare source feature(or plugin) key.
+ *
+ * @return feature(or plugin) key, feature id(or plugin id) + "#" + feature version(or plugin version)
+ */
+ public String getSourceKey() {
+ return this.sourceKey;
+ }
+
+ /**
+ * Return the compare destination feature(or plugin) key.
+ *
+ * @return feature(or plugin) key, feature id(or plugin id) + "#" + feature version(or plugin version)
+ * it can be <code>null</code> if the instance of this class represents a compare result of features
+ */
+ public String getDestinationKey() {
+ return this.destinationKey;
+ }
+
+ /**
+ * Return the compare result's version. If the new version is correct, it is the
+ * new version; if the new version is incorrect, it is the recommended
+ * version; if some error happened, it is <code>null</code>.
+ *
+ * @return version the version or <code>null</code>
+ */
+ public Version getVersion() {
+ return this.version;
+ }
+
+ /**
+ * returns change on the feature or plugin
+ * <p>
+ * The value of change is an int number of the following:
+ * <ul>
+ * <li>{@link IVersionCompare#ERROR_OCCURRED}</li>
+ * <li>{@link IVersionCompare#MAJOR_CHANGE}</li>
+ * <li>{@link IVersionCompare#MINOR_CHANGE}</li>
+ * <li>{@link IVersionCompare#NEW_ADDED}</li>
+ * <li>{@link IVersionCompare#NO_LONGER_EXIST}</li>
+ * <li>{@link IVersionCompare#MICRO_CHANGE}</li>
+ * <li>{@link IVersionCompare#QUALIFIER_CHANGE}</li>
+ * <li>{@link IVersionCompare#NO_CHANGE}</li>
+ * </ul>
+ * </p>
+ * @return change int number which indicates the overall change happened on a plugin or class
+ * @see IVersionCompare#ERROR_OCCURRED
+ * @see IVersionCompare#MAJOR_CHANGE
+ * @see IVersionCompare#MINOR_CHANGE
+ * @see IVersionCompare#NEW_ADDED
+ * @see IVersionCompare#NO_LONGER_EXIST
+ * @see IVersionCompare#MICRO_CHANGE
+ * @see IVersionCompare#QUALIFIER_CHANGE
+ * @see IVersionCompare#NO_CHANGE
+ */
+ public int getChange() {
+ return this.change;
+ }
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/ClassFileHelper.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/ClassFileHelper.java
new file mode 100755
index 000000000..69eeddd42
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/ClassFileHelper.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import java.io.*;
+import java.net.URL;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jdt.core.ToolFactory;
+import org.eclipse.jdt.core.util.IClassFileReader;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Helper class for dealing with class files.
+ */
+public class ClassFileHelper implements VersionCompareConstants {
+
+ /**
+ * Return a class file reader based on the given object or <code>null</code>.
+ */
+ public static IClassFileReader getReader(Object object) throws CoreException {
+ if (object instanceof String)
+ return getClassReaderFromFile(new File((String) object));
+ if (object instanceof File)
+ return getClassReaderFromFile((File) object);
+ if (object instanceof URL)
+ return getClassReaderFromURL((URL) object);
+ if (object instanceof InputStream) {
+ IClassFileReader fileReader = ToolFactory.createDefaultClassFileReader((InputStream) object, IClassFileReader.ALL);
+ return fileReader;
+ } else if (object instanceof IClassFileReader)
+ return (IClassFileReader) object;
+ else
+ // otherwise throw CoreException
+ throw new CoreException(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS.bind(Messages.JavaClassVersionCompare_unexpectedTypeMsg, object.getClass().getName()), null));
+ }
+
+ /**
+ * gets IClassFileReader of the java class denoted by <code>file</code>
+ * @param file java class file
+ * @return IClassFileReader instance or <code>null</code>if file type is wrong or any error occurred
+ */
+ private static IClassFileReader getClassReaderFromFile(File file) {
+ if (isGivenTypeFile(file, CLASS_FILE_EXTENSION))
+ return ToolFactory.createDefaultClassFileReader(file.getAbsolutePath(), IClassFileReader.ALL_BUT_METHOD_BODIES);
+ if (isGivenTypeFile(file, JAVA_FILE_EXTENSION))
+ return null;
+ return null;
+ }
+
+ /**
+ * Checks whether or not the given file potentially represents a given type file on the file-system.
+ *
+ * @param file File instance which denotes to a file on the file-system
+ * @param type file type(e.g. "java","class")
+ * @return <code>true</code> <code>file</code> exists and is a configuration file,
+ * <code>false</code> otherwise
+ */
+ private static boolean isGivenTypeFile(File file, String type) {
+ return file.isFile() && file.getName().endsWith(type);
+ }
+
+ /**
+ * Return a class file reader based on the contents of the given URL's input stream.
+ *
+ * @param url location of the class file
+ * @return the class file reader or <code>null</code>if any error occurred
+ */
+ private static IClassFileReader getClassReaderFromURL(URL url) {
+ try {
+ InputStream input = url.openStream();
+ try {
+ return ToolFactory.createDefaultClassFileReader(input, IClassFileReader.ALL_BUT_METHOD_BODIES);
+ } finally {
+ if (input != null) {
+ input.close();
+ input = null;
+ }
+ }
+ } catch (IOException e) {
+ //ignore, result will be checked outside
+ }
+ return null;
+ }
+
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CompareOptionFileHelper.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CompareOptionFileHelper.java
new file mode 100755
index 000000000..18a187a19
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CompareOptionFileHelper.java
@@ -0,0 +1,390 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.pde.tools.versioning.IVersionCompare;
+import org.eclipse.update.core.IIncludedFeatureReference;
+import org.eclipse.update.core.model.FeatureModel;
+import org.eclipse.update.core.model.PluginEntryModel;
+
+/**
+ * This class provides methods to process compare option property file, store the inclusive and exclusive
+ * information, check if a feature of plugin is need to be compared.
+ * <p>
+ * The properties in the compare option file are as following:
+ * <ul>
+ * <li>"exclude.os" - which indicates exclusive Operation Systems
+ * <li>"include.os" - which indicates inclusive Operation Systems
+ * <li>"exclude.ws" - which indicates exclusive windows system architecture specifications
+ * <li>"include.ws" - which indicates inclusive windows system architecture specifications
+ * <li>"exclude.arch" - which indicates exclusive optional system architecture specifications
+ * <li>"include.arch" - which indicates inclusive optional system architecture specifications
+ * <li>"exclude.nl" - which indicates exclusive optional locale language specifications
+ * <li>"include.nl" - which indicates inclusive optional locale language specifications
+ * <li>"exclude.features" - which indicates exclusive feature ids
+ * <li>"include.features" - which indicates inclusive feature ids
+ * <li>"exclude.plugins" - which indicates exclusive plugin ids
+ * <li>"include.plugins" - which indicates inclusive plugin ids
+ * </ul>
+ * </p>
+ *
+ */
+public class CompareOptionFileHelper implements VersionCompareConstants {
+
+ private Map optionTable = null;
+
+ /**
+ * constructor
+ * @param file compare option file
+ * @throws CoreException <p>if nested CoreException has been thrown
+ */
+ public CompareOptionFileHelper(File file) throws CoreException {
+ if (file == null)
+ return;
+ processVersioningOptionFile(file);
+ }
+
+ /**
+ * processes the compare option file denoted by <code>file</code>, and put
+ * property key as key, List of property values of the property key as value
+ * into a map.
+ *
+ *
+ * @param file compare option file
+ * @throws CoreException if <code>file</code> does not exist or any IOException has been thrown
+ */
+ private void processVersioningOptionFile(File file) throws CoreException {
+ Map table = new Hashtable();
+ InputStream inputStream = null;
+ Properties properties = new Properties();
+ try {
+ inputStream = new BufferedInputStream(new FileInputStream(file));
+ properties.load(inputStream);
+ } catch (FileNotFoundException fnfe) {
+ throw new CoreException(new Status(IStatus.ERROR, VersionCompareConstants.PLUGIN_ID, IStatus.ERROR, NLS.bind(Messages.VersionCompareDispatcher_fileNotFoundMsg, file.getAbsolutePath()), fnfe));
+ } catch (IOException ioe) {
+ throw new CoreException(new Status(IStatus.ERROR, VersionCompareConstants.PLUGIN_ID, IStatus.ERROR, NLS.bind(Messages.VersionCompareDispatcher_readPropertyFailedMsg, file.getAbsolutePath()), ioe));
+ } finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException ioe) {
+ throw new CoreException(new Status(IStatus.ERROR, VersionCompareConstants.PLUGIN_ID, IStatus.ERROR, NLS.bind(Messages.VersionCompareDispatcher_closeFileFailedMsg, file.getAbsolutePath()), ioe));
+ }
+ }
+ }
+ for (Iterator iterator = properties.keySet().iterator(); iterator.hasNext();) {
+ Object key = iterator.next();
+ String property = properties.getProperty((String) key);
+ if (property == null || property.trim().equals(VersionCompareConstants.EMPTY_STRING))
+ continue;
+ List propertyValueList;
+ // for feature or plugin inclusion, exclusion values, we convert them into Patterns
+ if (key.equals(IVersionCompare.INCLUDE_FEATURES_OPTION) || key.equals(IVersionCompare.EXCLUDE_FEATURES_OPTION) || key.equals(IVersionCompare.INCLUDE_PLUGINS_OPTION) || key.equals(IVersionCompare.EXCLUDE_PLUGINS_OPTION))
+ propertyValueList = generatePatternList(Arrays.asList(property.split(VersionCompareConstants.COMMA_MARK)));
+ else
+ propertyValueList = Arrays.asList(property.split(VersionCompareConstants.COMMA_MARK));
+ table.put(key, propertyValueList);
+ }
+ this.optionTable = table;
+ }
+
+ /*
+ * check the includes/excludes filters based on operating system
+ */
+ private boolean filterOS(Object object) {
+ List inclusionValueList = (List) optionTable.get(IVersionCompare.INCLUDE_OS_OPTION);
+ String[] propertyValue;
+ if (object instanceof IIncludedFeatureReference)
+ propertyValue = ((IIncludedFeatureReference) object).getOS() == null ? null : ((IIncludedFeatureReference) object).getOS().split(COMMA_MARK);
+ else if (object instanceof PluginEntryModel)
+ propertyValue = ((PluginEntryModel) object).getOS() == null ? null : ((PluginEntryModel) object).getOS().split(COMMA_MARK);
+ else
+ propertyValue = ((FeatureModel) object).getOS() == null ? null : ((FeatureModel) object).getOS().split(COMMA_MARK);
+ if (!inclusionMatch(propertyValue, inclusionValueList))
+ return false;
+ // inclusionMatch is true, do exclusionMatch
+ return !exclusionMatch(propertyValue, (List) optionTable.get(IVersionCompare.EXCLUDE_OS_OPTION));
+ }
+
+ /*
+ * check the includes/excludes filters based on windowing system
+ */
+ private boolean filterWS(Object object) {
+ List inclusionValueList = (List) optionTable.get(IVersionCompare.INCLUDE_WS_OPTION);
+ String[] propertyValue;
+ if (object instanceof IIncludedFeatureReference)
+ propertyValue = ((IIncludedFeatureReference) object).getWS() == null ? null : ((IIncludedFeatureReference) object).getWS().split(COMMA_MARK);
+ else if (object instanceof PluginEntryModel)
+ propertyValue = ((PluginEntryModel) object).getWS() == null ? null : ((PluginEntryModel) object).getWS().split(COMMA_MARK);
+ else
+ propertyValue = ((FeatureModel) object).getWS() == null ? null : ((FeatureModel) object).getWS().split(COMMA_MARK);
+ if (!inclusionMatch(propertyValue, inclusionValueList))
+ return false;
+ // inclusionMatch is true, do exclusionMatch
+ return !exclusionMatch(propertyValue, (List) optionTable.get(IVersionCompare.EXCLUDE_WS_OPTION));
+ }
+
+ /*
+ * check the includes/excludes filters based on system architecture
+ */
+ private boolean filterArch(Object object) {
+ List inclusionValueList = (List) optionTable.get(IVersionCompare.INCLUDE_ARCH_OPTION);
+ String[] propertyValue;
+ if (object instanceof IIncludedFeatureReference)
+ propertyValue = ((IIncludedFeatureReference) object).getOSArch() == null ? null : ((IIncludedFeatureReference) object).getOSArch().split(COMMA_MARK);
+ else if (object instanceof PluginEntryModel)
+ propertyValue = ((PluginEntryModel) object).getOSArch() == null ? null : ((PluginEntryModel) object).getOSArch().split(COMMA_MARK);
+ else
+ propertyValue = ((FeatureModel) object).getOSArch() == null ? null : ((FeatureModel) object).getOSArch().split(COMMA_MARK);
+ if (!inclusionMatch(propertyValue, inclusionValueList))
+ return false;
+ // inclusionMatch is true, do exclusionMatch
+ return !exclusionMatch(propertyValue, (List) optionTable.get(IVersionCompare.EXCLUDE_ARCH_OPTION));
+ }
+
+ /*
+ * check the includes/excludes filters based on the language
+ */
+ private boolean filterNL(Object object) {
+ List inclusionValueList = (List) optionTable.get(IVersionCompare.INCLUDE_NL_OPTION);
+ String[] propertyValue;
+ if (object instanceof IIncludedFeatureReference)
+ propertyValue = ((IIncludedFeatureReference) object).getNL() == null ? null : ((IIncludedFeatureReference) object).getNL().split(COMMA_MARK);
+ else if (object instanceof PluginEntryModel)
+ propertyValue = ((PluginEntryModel) object).getNL() == null ? null : ((PluginEntryModel) object).getNL().split(COMMA_MARK);
+ else
+ propertyValue = ((FeatureModel) object).getNL() == null ? null : ((FeatureModel) object).getNL().split(COMMA_MARK);
+ if (!inclusionMatch(propertyValue, inclusionValueList))
+ return false;
+ // inclusionMatch is true, do exclusionMatch
+ return !exclusionMatch(propertyValue, (List) optionTable.get(IVersionCompare.EXCLUDE_NL_OPTION));
+ }
+
+ /*
+ * check the includes/excludes filters based on feature identifiers
+ */
+ private boolean filterFeatures(Object object) throws CoreException {
+ List inclusionPatternList = (List) optionTable.get(IVersionCompare.INCLUDE_FEATURES_OPTION);
+ String id;
+ if (object instanceof IIncludedFeatureReference)
+ id = ((IIncludedFeatureReference) object).getVersionedIdentifier().getIdentifier();
+ else
+ id = ((FeatureModel) object).getFeatureIdentifier();
+ if (inclusionPatternList != null) {
+ if (isMatch(id, inclusionPatternList)) {
+ // inclusion match, do exclusion match
+ List exclusionPatternList = (List) optionTable.get(IVersionCompare.EXCLUDE_FEATURES_OPTION);
+ if (exclusionPatternList != null && isMatch(id, exclusionPatternList))
+ return false;
+ } else
+ return false;
+ } else {
+ // do exclusion match
+ List exclusionPatternList = (List) optionTable.get(IVersionCompare.EXCLUDE_FEATURES_OPTION);
+ if (exclusionPatternList != null && isMatch(id, exclusionPatternList))
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * check the includes/excludes filters based on plugin identifiers
+ */
+ private boolean filterPlugins(Object object) {
+ List inclusionPatternList = (List) optionTable.get(IVersionCompare.INCLUDE_PLUGINS_OPTION);
+ String id = ((PluginEntryModel) object).getPluginIdentifier();
+ if (inclusionPatternList != null) {
+ if (isMatch(id, inclusionPatternList)) {
+ // inclusion match, do exclusion match
+ List exclusionPatternList = (List) optionTable.get(IVersionCompare.EXCLUDE_PLUGINS_OPTION);
+ if (exclusionPatternList != null && isMatch(id, exclusionPatternList))
+ return false;
+ } else
+ return false;
+ } else {
+ // do exclusion match
+ List exclusionPatternList = (List) optionTable.get(IVersionCompare.EXCLUDE_PLUGINS_OPTION);
+ if (exclusionPatternList != null && isMatch(id, exclusionPatternList))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns a boolean value indicating whether or not the given object should be compared
+ * based on the includes and excludes filters.
+ * <p>
+ * The parameter can be of any of the following types:
+ * <ul>
+ * <li><code>IIncludedFeatureReference</code></li>
+ * <li><code>FeatureModel</code></li>
+ * <li><code>PluginEntryModel</code></li>
+ * </ul>
+ * </p>
+ *
+ * @param object the object to check
+ * @return <code>true</code> if we should compare and <code>false</code> otherwise
+ * @throws CoreException <p> if any nested CoreException has been thrown</p>
+ */
+ public boolean shouldCompare(Object object) throws CoreException {
+ if (!((object instanceof IIncludedFeatureReference) || (object instanceof PluginEntryModel) || (object instanceof FeatureModel)))
+ return false;
+ if (optionTable == null || optionTable.size() == 0)
+ // if inclusionTable is null, means everything need to be compared
+ return true;
+
+ // check the includes/excludes filters based on operating system
+ if (!filterOS(object))
+ return false;
+
+ // check the includes/excludes filters based on windowing system
+ if (!filterWS(object))
+ return false;
+
+ // check the includes/excludes filters based on system architecture
+ if (!filterArch(object))
+ return false;
+
+ // check the includes/excludes filters based on the language
+ if (!filterNL(object))
+ return false;
+
+ // check the includes/excludes filters based on feature or plugin identifiers
+ if ((object instanceof IIncludedFeatureReference) || (object instanceof FeatureModel))
+ return filterFeatures(object);
+ else
+ return filterPlugins(object);
+ }
+
+ /**
+ * checks whether <code>list1</code> contains at least one element of <code>list2</code>
+ * @param list1 List
+ * @param list2 List
+ * @return <code>true</code>if <code>list1</code> contains at least one element of <code>list2</code>,
+ * <code>false</code> otherwise
+ */
+ private boolean isIntersecting(List list1, List list2) {
+ for (Iterator iterator = list2.iterator(); iterator.hasNext();) {
+ Object key = iterator.next();
+ if (list1.contains(key))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * check whether given <code>values</code> and <code>inclusionValueList</code> has an intersection
+ * @param values String array
+ * @param inclusionValueList inclusion value list
+ * @return <code>true</code> if given <code>values</code> and <code>inclusionValueList</code> has an intersection
+ * <code>false</code> otherwise
+ */
+ private boolean inclusionMatch(String[] values, List inclusionValueList) {
+ if (values == null || inclusionValueList == null)
+ return true;
+ List propertyValue = Arrays.asList(values);
+ if (!isIntersecting(inclusionValueList, propertyValue))
+ // if propertyValue and inclusionValueList does not an intersection, return false
+ return false;
+ return true;
+ }
+
+ /**
+ * check whether given <code>values</code> are included the <code>exclusionValueList</code>
+ * @param values String array
+ * @param exclusionValueList exclusion value list
+ * @return <code>true</code> if given <code>values</code> are included the <code>exclusionValueList</code>
+ * <code>false</code> otherwise
+ */
+ private boolean exclusionMatch(String[] values, List exclusionValueList) {
+ if (values == null || exclusionValueList == null)
+ return false;
+ List propertyValue = Arrays.asList(values);
+ if (!isIncluded(exclusionValueList, propertyValue))
+ // if propertyValue are not included in exclusionValuList, return false
+ return false;
+ return true;
+ }
+
+ /**
+ * checks whether <code>list1</code> contains all the elements of <code>list2</code>
+ * @param list1 List
+ * @param list2 List
+ * @return <code>true</code>if <code>list1</code> contains all the elements of <code>list2</code>,
+ * <code>false</code> otherwise
+ */
+ private boolean isIncluded(List list1, List list2) {
+ for (Iterator iterator = list2.iterator(); iterator.hasNext();) {
+ Object key = iterator.next();
+ if (!list1.contains(key))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * checks whether the <code>string</code> matches the <code>regex</code>
+ * @param string String need to be matched
+ * @param patternList List contains Patterns
+ * @return <code>true</code>if the <code>string</code> matches the <code>regex</code>
+ * <code>false</code>otherwise
+ */
+ private boolean isMatch(String string, List patternList) {
+ for (Iterator iterator = patternList.iterator(); iterator.hasNext();) {
+ Pattern pattern = (Pattern) iterator.next();
+ Matcher matcher = pattern.matcher(string);
+ if (matcher.matches())
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * generates Pattern instances from each String in <code>list</code>
+ * @param list List contains Strings
+ * @return List contains Pattern instances
+ */
+ private List generatePatternList(List list) {
+ List newList = new ArrayList();
+ for (Iterator iterator = list.iterator(); iterator.hasNext();) {
+ newList.add(Pattern.compile(generateRegex((String) iterator.next())));
+ }
+ return newList;
+ }
+
+ /**
+ * generates regular expression from <code>string</code>
+ * @param string
+ * @return regular expression
+ */
+ private String generateRegex(String string) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < string.length(); i++) {
+ char singleChar = string.charAt(i);
+ if (singleChar == START_CHAR)
+ // convert '*' to ".*"
+ buffer.append(WILD_CAST_STRING);
+ else if (singleChar == DOT_CHAR)
+ // convert '.' to "\."
+ buffer.append(DOT_QUOTE_STRING);
+ else
+ buffer.append(singleChar);
+ }
+ return buffer.toString();
+ }
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CompareResult.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CompareResult.java
new file mode 100755
index 000000000..8cd7edd5b
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/CompareResult.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.pde.tools.versioning.ICompareResult;
+
+/**
+ * This class represents compare result of a plugin or class
+ */
+public class CompareResult implements ICompareResult {
+ int change;
+ MultiStatus status;
+
+ /**
+ * constructor
+ *
+ * @param change change on a feature or plugin
+ * @param status contains messages created when verify a plugin or class
+ */
+ public CompareResult(int change, MultiStatus status) {
+ this.change = change;
+ this.status = status;
+ }
+
+ /**
+ * gets status which contains messages created when verify a plugin or class
+ * @return MultiStatus instance
+ */
+ public MultiStatus getResultStatus() {
+ return this.status;
+ }
+
+ /**
+ * get change on a plugin or class
+ * @return change
+ */
+ public int getChange() {
+ return this.change;
+ }
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/FeatureModelTable.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/FeatureModelTable.java
new file mode 100755
index 000000000..2c3232ca1
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/FeatureModelTable.java
@@ -0,0 +1,386 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.pde.tools.versioning.IVersionCompare;
+import org.eclipse.update.configurator.ConfiguratorUtils;
+import org.eclipse.update.configurator.IPlatformConfiguration;
+import org.eclipse.update.configurator.IPlatformConfiguration.ISiteEntry;
+import org.eclipse.update.core.model.FeatureModel;
+import org.eclipse.update.core.model.FeatureModelFactory;
+import org.xml.sax.SAXException;
+
+/**
+ * FeatureModels use two hashtables to store FeatureModels and
+ * feature.xml file locations. It provides methods to access
+ * information of FeatureModels
+ *
+ *
+ */
+public class FeatureModelTable implements VersionCompareConstants {
+
+ class TableEntry {
+ FeatureModel model;
+ IPath location;
+
+ TableEntry(FeatureModel model, IPath location) {
+ super();
+ this.model = model;
+ this.location = location;
+ }
+ }
+
+ // indicate the FeatureModels is from a configuration file or a directory
+ private boolean isConfiguration;
+ // table for storing features. key is a string which is the feature identifier. values are instances
+ // of the TableEntry inner class as defined by this type.
+ private Map featureTable;
+ // MultiStatus which stores error or warning message
+ private MultiStatus status;
+ //
+ private CompareOptionFileHelper compareOptionFileHelper;
+
+ /**
+ * constructor
+ *
+ * @param object it could be a String, File, or URL which denotes to a eclipse configuration file or a feature directory
+ * @param helper CompareOptionFileHelper instance
+ * @throws CoreException <p>if any nested CoreException has been thrown
+ */
+ public FeatureModelTable(Object object, CompareOptionFileHelper helper) throws CoreException {
+ if (object instanceof URL)
+ initialize((URL) object, helper);
+ else if (object instanceof File)
+ initialize((File) object, helper);
+ else if (object instanceof String)
+ initialize(new File((String) object), helper);
+ }
+
+ /**
+ * initialization
+ *
+ * @param configURL URL instance which denotes an eclipse configuration XML file
+ * @throws CoreException
+ */
+ private void initialize(URL configURL, CompareOptionFileHelper helper) throws CoreException {
+ compareOptionFileHelper = helper;
+ status = new MultiStatus(PLUGIN_ID, IStatus.OK, Messages.FeatureVersionCompare_errorReasonMsg, null);
+ featureTable = new HashMap(0);
+ IPlatformConfiguration config;
+ // get configuration
+ try {
+ config = ConfiguratorUtils.getPlatformConfiguration(configURL);
+ } catch (IOException ioe) {
+ throw new CoreException(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.FeatureModelTable_couldNotReadConfigFileMsg, configURL.getFile()), ioe));
+ }
+ // generate Lists which store URLs of feature entries included in configuration1 and configuration2
+ List featureList = generateFeatureEntryList(configURL, config);
+ if (featureList == null) {
+ status.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.FeatureVersionCompare_noFeaturesFoundInConfigMsg, configURL), null));
+ }
+ // generate feature model maps and feature address maps
+ generateFeatureModelTable(config, featureList);
+ // this is a configuration file
+ isConfiguration = true;
+ }
+
+ /**
+ * initialization
+ *
+ * @param file File instance which denotes an directory of FileSystem
+ * @param map inclusive map
+ * @throws CoreException
+ */
+ private void initialize(File file, CompareOptionFileHelper helper) throws CoreException {
+ // check to see if we are pointing to configuration files
+ if (isConfiguration(file)) {
+ try {
+ initialize(file.toURL(), helper);
+ return;
+ } catch (MalformedURLException e) {
+ throw new CoreException(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.FeatureModelTable_urlConvertErrorMsg, file.getAbsolutePath()), e));
+ }
+ }
+ compareOptionFileHelper = helper;
+ status = new MultiStatus(PLUGIN_ID, IStatus.OK, Messages.FeatureVersionCompare_errorReasonMsg, null);
+ featureTable = new HashMap(0);
+ // check to see if we have feature directories
+ if (isFeaturesDirectory(file)) {
+ // if file are directory, get sub feature directories under it
+ File[] subFeatures = file.listFiles(new VersioningDirFilter());
+ // check if there is any feature directory under directory1 and directory2
+ if (subFeatures == null || subFeatures.length == 0) {
+ status.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.FeatureVersionCompare_noFeatureFoundMsg, file), null));
+ return;
+ }
+ // generate feature model maps
+ generateFeatureModelTable(subFeatures);
+ if (featureTable.size() == 0)
+ status.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.FeatureVersionCompare_noFeatureFoundMsg, file), null));
+ // this is a directory
+ isConfiguration = false;
+ return;
+ }
+ status.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.FeatureModelTable_featureSourceErrorMsg, file), null));
+ }
+
+ /**
+ * check whether or not the given file potentially represents a platform configuration file on the file-system.
+ *
+ * @return <code>true</code> if <code>file</code> is a configuration file
+ * <code>false</code> otherwise
+ */
+ private boolean isConfiguration(File file) {
+ IPath path = new Path(file.getAbsolutePath());
+ return file.isFile() && CONFIGURATION_FILE_NAME.equalsIgnoreCase(path.lastSegment());
+ }
+
+ /**
+ * check whether or not the given file represents a features directory.
+ *
+ * @return <code>true</code> if <code>file</code> is a directory
+ * <code>false</code> otherwise
+ */
+ private boolean isFeaturesDirectory(File file) {
+ return file.isDirectory();
+ }
+
+ /**
+ * extracts FeatureModels of features in <code>featureFiles</code>, and
+ * put them into hashtable
+ * Key is feature id
+ * Value is FeatureModel instance of the feature
+ *
+ * @param featureFiles array of File instances
+ * @throws CoreException <p>if any nested CoreException has been thrown</p>
+ */
+ private void generateFeatureModelTable(File[] featureFiles) throws CoreException {
+ File[] featureXMLFile;
+ for (int i = 0; i < featureFiles.length; i++) {
+ // get "feature.xml" file under the feature directory
+ featureXMLFile = featureFiles[i].listFiles(new VersioningFeatureFileFilter(FEATURES_FILE_NAME));
+ if (featureXMLFile == null || featureXMLFile.length == 0) {
+ // there is no "feature.xml" file found
+ continue;
+ }
+ // parse the "feature.xml" file and get its FeatureModel object
+ FeatureModel fm = parseFeature(featureXMLFile[0].getAbsolutePath());
+ if (compareOptionFileHelper == null ? true : compareOptionFileHelper.shouldCompare(fm))
+ // add the feature and its information to the table
+ featureTable.put(fm.getFeatureIdentifier(), new TableEntry(fm, new Path(featureXMLFile[0].getAbsolutePath())));
+ }
+ }
+
+ /**
+ * Generates a list which contains locations of feature entries included in <code>config</code>
+ * represented by <code>IPath</code> objects.
+ *
+ * @param config configuration
+ * @return List instance contains IPaths of feature entries included in <code>config</code>; return is <code>null</code>
+ * if there is no feature entry has been found in <code>config</code>
+ */
+ private List generateFeatureEntryList(URL configURL, IPlatformConfiguration config) {
+ // get site entries from the configuration
+ ISiteEntry[] sites = config.getConfiguredSites();
+ // create a new List
+ ArrayList list = new ArrayList(0);
+ for (int i = 0; i < sites.length; i++) {
+ IPath sitePath;
+ // get URL of site
+ URL siteURL = sites[i].getURL();
+ if (siteURL.getProtocol().equals(PLATFORM_PROTOCOL)) {
+ sitePath = new Path(configURL.getPath());
+ // path points to the platform.xml file in the update bundle's
+ // location in the configuration area so work our way back
+ // to the root of the Eclipse install.
+ sitePath = sitePath.removeLastSegments(3);
+ } else {
+ sitePath = new Path(siteURL.getPath());
+ }
+ String[] features = sites[i].getFeatures();
+ // create a path for each feature entry included in the site
+ for (int j = 0; j < features.length; j++)
+ list.add(sitePath.append(features[j]).append(FEATURES_FILE_NAME));
+ }
+ return list.size() == 0 ? null : list;
+ }
+
+ /**
+ * extracts FeatureModels of features in configuration file denoted by <code>config</code>,
+ * Key is feature id
+ * Value is FeatureModel object
+ *
+ * @param config configuration
+ * @param list list of feature locations (IPath)
+ * @throws CoreException <p>if any nested CoreException has been thrown</p>
+ */
+ private void generateFeatureModelTable(IPlatformConfiguration config, List list) throws CoreException {
+ // create a map which contains the feature id and version of the feature entries in the configuration
+ for (Iterator features = list.iterator(); features.hasNext();) {
+ IPath location = null;
+ try {
+ // get location of feature
+ location = (IPath) features.next();
+ // get FeatureModel
+ FeatureModel fm = parseFeature(location.toFile().toURL().openStream());
+ if (compareOptionFileHelper == null ? true : compareOptionFileHelper.shouldCompare(fm))
+ featureTable.put(fm.getFeatureIdentifier(), new TableEntry(fm, location));
+ } catch (IOException ioe) {
+ status.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.FeatureVersionCompare_featureFileErrorMsg, location.toOSString()), ioe));
+ continue;
+ }
+ }
+ }
+
+ /**
+ * Return a new status object populated with the given information.
+ *
+ * @param severity severity of status
+ * @param code indicates type of this IStatus instance, it could be one of: FEATURE_OVERALL_STATUS,
+ * FEATURE_DETAIL_STATUS, PLUGIN_OVERALL_STATUS, PLUGIN_DETAIL_STATUS, PROCESS_ERROR_STATUS,
+ * CLASS_OVERALL_STATUS, CLASS_DETAIL_STATUS
+ * @param message the status message
+ * @param exception exception which has been caught, or <code>null</code>
+ * @return the new status object
+ */
+ private IStatus resultStatusHandler(int severity, int code, String message, Exception exception) {
+ if (message == null) {
+ if (exception != null)
+ message = exception.getMessage();
+ // extra check because the exception message can be null
+ if (message == null)
+ message = EMPTY_STRING;
+ }
+ return new Status(severity, PLUGIN_ID, code, message, exception);
+ }
+
+ /**
+ * Parses the feature manifest file denoted by the given input stream and returns
+ * the resulting feature model object. The stream is closed when this method is returned.
+ *
+ * @param input the stream pointing to the feature manifest
+ * @return resulting feature model object
+ * @throws CoreException if there was an error parsing the input stream
+ */
+ private FeatureModel parseFeature(InputStream input) throws CoreException {
+ try {
+ FeatureModelFactory factory = new FeatureModelFactory();
+ return factory.parseFeature(input);
+ } catch (SAXException saxe) {
+ throw new CoreException(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS, null, saxe));
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * Parses the feature manifest file located in the file-system at the given path. Return
+ * the resulting feature model object.
+ *
+ * @param path the location of the feature manifest
+ * @return the resulting feature model
+ * @throws CoreException if there was an error parsing the feature manifest
+ */
+ private FeatureModel parseFeature(String path) throws CoreException {
+ try {
+ InputStream fis = new BufferedInputStream(new FileInputStream(path));
+ // return FeatureModel of feature.xml the FielInputStream passed to parseFeature(InputStream)
+ // will be closed in parseFeature(InputStream featureInputStream) method.
+ return parseFeature(fis);
+ } catch (FileNotFoundException fnfe) {
+ throw new CoreException(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.FeatureModelTable_featureFileParseErrorMsg, path), fnfe));
+ }
+ }
+
+ /**
+ * checks if the FeatureModels included in the current object are from a configuration file
+ * @return <code>true</code> if the current object contains FeatureModels from a configuration file
+ * <code>false</code> otherwise
+ */
+ public boolean isConfiguration() {
+ return isConfiguration;
+ }
+
+ /**
+ * checks if there is any error occurred when generate the current object
+ * @return <code>true</code> if there is no error occurred
+ * <code>false</code> otherwise
+ */
+ public boolean isOK() {
+ return status.isOK();
+ }
+
+ /**
+ * gets location of the feature which is denoted by <code>id</code>
+ * @param id feature id
+ * @return location of feature <code>id</code>
+ */
+ public IPath getLocation(String id) {
+ TableEntry entry = (TableEntry) featureTable.get(id);
+ return entry == null ? null : entry.location;
+ }
+
+ /**
+ * gets version of the feature which is denoted by <code>id</code>
+ * @param id feature id
+ * @return feature version(String)
+ */
+ public String getVersion(String id) {
+ TableEntry entry = (TableEntry) featureTable.get(id);
+ return entry == null ? null : entry.model.getFeatureVersion();
+ }
+
+ /**
+ * gets status of the current FeatureModelTable object
+ * @return status
+ */
+ public IStatus getStatus() {
+ return status;
+ }
+
+ /**
+ * gets FeatureModel instance of the feature denoted by <code>id</code>
+ * @param id feature id
+ * @return Object instance which presents a FeatureModel instance
+ */
+ public Object getFeatureModel(Object id) {
+ TableEntry entry = (TableEntry) featureTable.get(id);
+ return entry == null ? null : entry.model;
+ }
+
+ /**
+ * gets number of FeatureModel instance included in the current FeatureModelTable instance
+ * @return number of FeatureModel instance
+ */
+ public int size() {
+ return featureTable.size();
+ }
+
+ /**
+ * gets a Set view of the keys contained in the current FeatureModelTable instance
+ * @return a set view of keys contained in the current FeatureModelTable instance
+ */
+ public Set getKeySet() {
+ return featureTable.keySet();
+ }
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/FeatureVersionCompare.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/FeatureVersionCompare.java
new file mode 100755
index 000000000..d057e0702
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/FeatureVersionCompare.java
@@ -0,0 +1,811 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import java.io.File;
+import java.net.URL;
+import java.util.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.ManifestElement;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.pde.tools.versioning.IVersionCompare;
+import org.eclipse.update.core.IIncludedFeatureReference;
+import org.eclipse.update.core.model.FeatureModel;
+import org.eclipse.update.core.model.PluginEntryModel;
+import org.osgi.framework.Version;
+
+/**
+ * VersionCompare
+ *
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare
+ */
+public class FeatureVersionCompare implements VersionCompareConstants {
+ // MultiStatus instance used to store error or warning messages of features and plugin entries
+ private MultiStatus finalResult;
+ // Map used to store ICompreResult instances of verified features
+ private Map verifiedFeatureTable;
+ // Map used to store ICompreResult instances of verified plugins
+ private Map verifiedPluginTable;
+ // FeatureModelTables used to store FeatureModels
+ private FeatureModelTable featureModelTable1;
+ private FeatureModelTable featureModelTable2;
+ //
+ private PluginVersionCompare pluginVersionCompare;
+ //
+ private CompareOptionFileHelper compareOptionFileHelper;
+ // monitor related variables
+ private VersioningProgressMonitorWrapper monitorWrapper;
+ //
+ private boolean needPluginCompare;
+ //
+ private long startTime;
+ private boolean DEBUG = false;
+ private static final String DEBUG_OPTION = VersionCompareConstants.PLUGIN_ID + "/debug/features"; //$NON-NLS-1$
+
+ /**
+ * Constructor
+ */
+ public FeatureVersionCompare() {
+ pluginVersionCompare = new PluginVersionCompare();
+ DEBUG = Activator.getBooleanDebugOption(DEBUG_OPTION);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkFeatureVersions(URL, URL, boolean, Map)
+ */
+ public IStatus checkFeatureVersions(URL configURL1, URL configURL2, boolean comparePlugins, File optionFile, IProgressMonitor monitor) throws CoreException {
+ return compareMain(configURL1, configURL2, comparePlugins, optionFile, monitor);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkFeatureVersions(java.lang.String, java.lang.String, boolean, Map)
+ */
+ public IStatus checkFeatureVersions(String path1, String path2, boolean comparePlugins, File optionFile, IProgressMonitor monitor) throws CoreException {
+ return checkFeatureVersions(new File(path1), new File(path2), comparePlugins, optionFile, monitor);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkFeatureVersions(File, File, boolean, Map)
+ */
+ public IStatus checkFeatureVersions(File file1, File file2, boolean comparePlugins, File optionFile, IProgressMonitor monitor) throws CoreException {
+ // check to see if we are pointing to two configuration files or two directories
+ if ((isConfiguration(file1) && isConfiguration(file2)) || (isFeaturesDirectory(file1) && isFeaturesDirectory(file2))) {
+ return compareMain(file1, file2, comparePlugins, optionFile, monitor);
+ }
+ return resultStatusHandler(IStatus.WARNING, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.FeatureVersionCompare_inputErrorMsg, file1, file2), null);
+ }
+
+ /**
+ * compare main method
+ * @param object1 URL, String, File instance which denotes a directory or a configuration file
+ * @param object2 URL, String, File instance which denotes a directory or a configuration file
+ * @param comparePlugins <code>true</code>plugins need to be compared as object, <code>false</code> just to flat comparison
+ * @param optionFile File instance which denotes a compare option file
+ * @param monitor IProgressMonitor instance
+ * @return IStatus instance which contains message generated during comparing
+ * @throws CoreException <p>if any nested CoreException has been thrown</p>
+ */
+ private IStatus compareMain(Object object1, Object object2, boolean comparePlugins, File optionFile, IProgressMonitor monitor) throws CoreException {
+ try {
+ monitor = VersioningProgressMonitorWrapper.monitorFor(monitor);
+ monitorWrapper = new VersioningProgressMonitorWrapper(monitor);
+ if (optionFile != null)
+ // generate CompareOptionFileHelper instance
+ compareOptionFileHelper = new CompareOptionFileHelper(optionFile);
+ // generate a MultiStatus instance to store compare result
+ finalResult = new MultiStatus(PLUGIN_ID, IStatus.OK, Messages.FeatureVersionCompare_errorReasonMsg, null);
+ // generate verified features and plugins maps
+ verifiedFeatureTable = new Hashtable(0);
+ verifiedPluginTable = new Hashtable(0);
+ this.needPluginCompare = comparePlugins;
+ // begin task
+ monitorWrapper.beginTask(Messages.FeatureVersionCompare_verifyingFeatureMsg, 100);
+ // generate feature model maps
+ featureModelTable1 = new FeatureModelTable(object1, compareOptionFileHelper);
+ monitorWrapper.worked(comparePlugins ? 5 : 30);
+ featureModelTable2 = new FeatureModelTable(object2, compareOptionFileHelper);
+ monitorWrapper.worked(comparePlugins ? 5 : 30);
+ if (!featureModelTable1.isOK()) {
+ finalResult.merge(featureModelTable1.getStatus());
+ }
+ if (!featureModelTable2.isOK()) {
+ finalResult.merge(featureModelTable2.getStatus());
+ }
+ // if featureModelTable1 or featureModelTable2 is empty, we return here
+ if (featureModelTable1.size() == 0 || featureModelTable2.size() == 0) {
+ return finalResult;
+ }
+ compareFeatures();
+ monitorWrapper.worked(comparePlugins ? 90 : 40);
+ return finalResult;
+ } finally {
+ monitorWrapper.done();
+ }
+ }
+
+ /**
+ * check whether or not the given file potentially represents a platform configuration file on the file-system.
+ *
+ * @return <code>true</code> if <code>file</code> is a configuration file
+ * <code>false</code> otherwise
+ */
+ private boolean isConfiguration(File file) {
+ return file.isFile() && CONFIGURATION_FILE_NAME.equalsIgnoreCase(new Path(file.getAbsolutePath()).lastSegment());
+ }
+
+ /**
+ * check whether or not the given file represents a features directory.
+ *
+ * @return <code>true</code> if <code>file</code> is a directory
+ * <code>false</code> otherwise
+ */
+ private boolean isFeaturesDirectory(File file) {
+ return file.isDirectory();
+ }
+
+ /**
+ * Add the given compare result to the list of already processed features.
+ *
+ * @param result the compare result
+ */
+ private void featureProcessed(CheckedItem result) {
+ verifiedFeatureTable.put(result.getSourceKey(), result);
+ }
+
+ /**
+ * Add the given compare result to the list of already processed plugins.
+ *
+ * @param result the compare result
+ */
+ private void pluginProcessed(CheckedItem result) {
+ verifiedPluginTable.put(result.getSourceKey()+KEY_SEPARATOR+ result.getDestinationKey(), result);
+ }
+
+ /**
+ * Verifies every version of feature included in featureModelTable1 based on the feature which has the same feature
+ * id in featureModelTable2, and generates an overall result as an VersioningMultiStatus instance
+ *
+ * @throws CoreException <p>if any nested CoreException has been thrown</p>
+ */
+ private void compareFeatures() throws CoreException {
+ startTime = System.currentTimeMillis();
+ // compare features
+ for (Iterator keys = featureModelTable1.getKeySet().iterator(); keys.hasNext();) {
+ if (monitorWrapper.isCanceled())
+ throw new OperationCanceledException();
+ // get a key (feature ID) from the new features map
+ Object key = keys.next();
+ FeatureModel newFeatureModel = (FeatureModel) (featureModelTable1.getFeatureModel(key));
+ // check if the feature has been checked or not
+ if (searchFeatureResult(newFeatureModel.getFeatureIdentifier() + KEY_SEPARATOR + newFeatureModel.getFeatureVersion()) == null) {
+ // if the feature has not been checked, we check it and add the result to status list
+ featureProcessed(verifyNewFeatureVersion(newFeatureModel, (FeatureModel) featureModelTable2.getFeatureModel(key), monitorWrapper.getSubMonitor((needPluginCompare ? 90 : 40) / featureModelTable1.size())));
+ }
+ }
+ debug("Feature Compare Time: " + (System.currentTimeMillis() - startTime) + " milliseconds"); //$NON-NLS-1$//$NON-NLS-2$
+ debug("Total message number: " + finalResult.getChildren().length); //$NON-NLS-1$
+ }
+
+ /*
+ * Log the given debug message.
+ */
+ private void debug(String message) {
+ if (DEBUG)
+ Activator.debug(message);
+ }
+
+ /**
+ * Compares <code>featureModel1</code> to <code>featureModel2</code> to check if the version of <code>featureModel1</code> is correct or not;
+ * <code>featureModel1</code> and <code>featureModel2</code> have the same feature ID
+ *
+ * @param featureModel1 the FeatureModel instance
+ * @param featureModel2 the FeatureModel instance
+ * @return result of verification encapsulated in an IStatus instance
+ * @throws CoreException <p>if any nested CoreException has been thrown</p>
+ */
+ private CheckedItem verifyNewFeatureVersion(FeatureModel featureModel1, FeatureModel featureModel2, IProgressMonitor monitor) throws CoreException {
+ // get feature id
+ String id = featureModel1.getFeatureIdentifier();
+ // get versions of featureModel1
+ Version version1 = new Version(featureModel1.getFeatureVersion());
+ // check if featureModel2 is null, if it's null, we consider it as new added
+ if (featureModel2 == null) {
+ Object[] msg = {id, version1, featureModelTable1.getLocation(id)};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.FEATURE_OVERALL_STATUS, NLS.bind(Messages.FeatureVersionCompare_newIntroducedFeatureMsg, msg), null));
+ return new CheckedItem(id + KEY_SEPARATOR + featureModel1.getFeatureVersion(), null, new Version(featureModel1.getFeatureVersion()), IVersionCompare.NEW_ADDED);
+ }
+ // get versions of featureModel2
+ Version version2 = new Version(featureModel2.getFeatureVersion());
+ // compare featureModel1 to featureModel2
+ int result = checkFeatureChange(featureModel1, featureModel2, monitor);
+ // some versions of included features or plugins are wrong
+ if (result == IVersionCompare.ERROR_OCCURRED) {
+ Object[] msg = {id, version1, featureModelTable1.getLocation(id)};
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.FEATURE_OVERALL_STATUS, NLS.bind(Messages.FeatureVersionCompare_nestedErrorOccurredMsg, msg), null));
+ return new CheckedItem(id + KEY_SEPARATOR + featureModel1.getFeatureVersion(), null, null, result);
+ }
+ // get the recommended version
+ Version recommendedVersion = recommendVersion(version2, result);
+ // check if version1 is correct or not
+ if (!isNewVersionValid(version1, recommendedVersion, result)) {
+ Object[] msg = new Object[] {id, version1, featureModelTable1.getLocation(id), recommendedVersion};
+ if (result == IVersionCompare.QUALIFIER_CHANGE) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.FEATURE_OVERALL_STATUS, NLS.bind(Messages.FeatureVersionCompare_incorrectNewVersionMsg2, msg), null));
+ } else {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.FEATURE_OVERALL_STATUS, NLS.bind(Messages.FeatureVersionCompare_incorrectNewVersionMsg, msg), null));
+ }
+ return new CheckedItem(id + KEY_SEPARATOR + featureModel1.getFeatureVersion(), null, recommendedVersion, result);
+ }else{
+ // check if version has been increased properly
+ int change = checkVersionChange(version1, version2);
+ if (change < result) {
+ Object[] msg = new Object[] {id, version1, featureModelTable1.getLocation(id), getVersionName(result), getVersionName(change)};
+ finalResult.merge(resultStatusHandler(IStatus.WARNING, IVersionCompare.FEATURE_OVERALL_STATUS, NLS.bind(Messages.FeatureVersionCompare_versionChangeIncorrectMsg, msg), null));
+ return new CheckedItem(id + KEY_SEPARATOR + version1.toString(), null, version1, change);
+ }
+ return new CheckedItem(id + KEY_SEPARATOR + version1.toString(), null, version1, result);
+ }
+ }
+
+ /**
+ * gets String which represent type of version denoted by <code>versionType</code>
+ * @param versionType int number
+ * @return String
+ */
+ private String getVersionName(int versionType){
+ switch (versionType){
+ case IVersionCompare.MAJOR_CHANGE: return "Major"; //$NON-NLS-1$
+ case IVersionCompare.MINOR_CHANGE: return "Minor"; //$NON-NLS-1$
+ case IVersionCompare.MICRO_CHANGE: return "Micro"; //$NON-NLS-1$
+ case IVersionCompare.QUALIFIER_CHANGE: return "Qualify"; //$NON-NLS-1$
+ case IVersionCompare.NO_CHANGE: return "NoChange"; //$NON-NLS-1$
+ default: return EMPTY_STRING;
+ }
+ }
+
+ /**
+ * Compares included features and plugins in <code>featureModel1</code> to those in <code>featureModel2</code>.
+ * Check if there is any change from <code>featureModel2</code> to <code>feaureModel1</code>
+ *
+ * @param featureModel1 FeatureModel instance
+ * @param featureModel2 FeatureModel instance
+ * @return change with the highest priority from <code>featureModel2</code> to <code>featureModel1</code>
+ * @throws CoreException <p>if any nested CoreException has been thrown</p>
+ */
+ private int checkFeatureChange(FeatureModel featureModel1, FeatureModel featureModel2, IProgressMonitor monitor) throws CoreException {
+ int overallChange = IVersionCompare.NO_CHANGE;
+ String id = featureModel1.getFeatureIdentifier();
+ Version version1 = new Version(featureModel1.getFeatureVersion());
+ Version version2 = new Version(featureModel2.getFeatureVersion());
+ // compare feature version first
+ if (version1.compareTo(version2) < 0) {
+ Object[] msg = {id, version1, featureModelTable1.getLocation(id), version2, featureModelTable2.getLocation(id)};
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.FEATURE_OVERALL_STATUS, NLS.bind(Messages.FeatureVersionCompare_newVersionLowerThanOldMsg, msg), null));
+ }
+ // get IncludedFeatureReference, PluginEntries of featureModel1
+ IIncludedFeatureReference[] includedFeatures1 = featureModel1.getFeatureIncluded();
+ PluginEntryModel[] pluginEntries1 = featureModel1.getPluginEntryModels();
+ // get IncludedFeatureReference, PluginEntries of featureModel2
+ IIncludedFeatureReference[] includedFeatures2 = featureModel2.getFeatureIncluded();
+ PluginEntryModel[] pluginEntries2 = featureModel2.getPluginEntryModels();
+ try {
+ monitor.beginTask(NLS.bind(Messages.FeatureVersionCompare_comparingFeatureMsg, id + UNDERSCORE_MARK + version1.toString()), 10);
+ // compare IncludedFeatureReferences in featureModel1 with those in featureModel2
+ overallChange = Math.min(overallChange, compareReferences(id, includedFeatures1, includedFeatures2, monitorWrapper.getSubMonitor(5)));
+ // compare PluginEntries in featureModel1 with those in featureModel2
+ overallChange = Math.min(overallChange, compareReferences(id, pluginEntries1, pluginEntries2, monitorWrapper.getSubMonitor(5)));
+ // return the version change with the highest priority
+ return overallChange;
+ } finally {
+ monitor.done();
+ }
+ }
+
+ /**
+ * Generates and returns a recommended version based on the given version and change.
+ *
+ * @param version the current version
+ * @param change the degree of change
+ * @return the recommended new version or <code>null</code> if the change is IVersionCompare.ERROR_OCCURRED
+ * or the change is not an expected value
+ */
+ private Version recommendVersion(Version version, int change) {
+ // get major, minor, service of version
+ int major = version.getMajor();
+ int minor = version.getMinor();
+ int micro = version.getMicro();
+ String qualifier = version.getQualifier();
+ // update major, minor, service based on the compare result
+ switch (change) {
+ case IVersionCompare.ERROR_OCCURRED :
+ return null;
+ case IVersionCompare.MAJOR_CHANGE : {
+ major++;
+ minor = 0;
+ micro = 0;
+ qualifier = EMPTY_STRING;
+ break;
+ }
+ // NOT_EXIST, NEW_ADDED are currently treated as minor change
+ case IVersionCompare.NO_LONGER_EXIST :
+ case IVersionCompare.NEW_ADDED :
+ case IVersionCompare.MINOR_CHANGE : {
+ minor++;
+ micro = 0;
+ qualifier = EMPTY_STRING;
+ break;
+ }
+ case IVersionCompare.MICRO_CHANGE : {
+ micro++;
+ qualifier = EMPTY_STRING;
+ break;
+ }
+ case IVersionCompare.QUALIFIER_CHANGE : {
+ // TODO increase qualifier
+ break;
+ }
+ case IVersionCompare.NO_CHANGE : {
+ // if there is no change, just return the version
+ return version;
+ }
+ default : {
+ return null;
+ }
+ }
+ // generate recommended version
+ return new Version(major, minor, micro, qualifier);
+ }
+
+ /**
+ * Checks if the <code>version1</code> is valid, based on <code>version2</code> and <code>change</code>
+ * from <code>version2</code> to <code>version1</code>
+ *
+ * @param version1 feature version
+ * @param version2 feature version
+ * @param change change from <code>version2</code> to <code>version1</code>
+ * @return <code>true</code> if version1 is correct and <code>false</code> otherwise
+ */
+ private boolean isNewVersionValid(Version version1, Version version2, int change) {
+ if (change == IVersionCompare.QUALIFIER_CHANGE) {
+ // compare qualifier version. We currently don't increase qualifier version if there is
+ // QUALIFIER_CHANGE,we need the version1 be big than version2
+ return version1.compareTo(version2) > 0;
+ }
+ // compare qualifier version
+ return version1.compareTo(version2) >= 0;
+ }
+
+ /**
+ * Compares feature version(or plugin entry versions) in <code>references1</code> to those in <code>references2</code>.
+ * Check if there is any version change from <code>references2</code> to <code>references1</code>. The change with
+ * the highest priority will be returned
+ *
+ * @param parentID id of the feature which these features(or plugin entries) belong to
+ * @param references1 array of included plugins or features
+ * @param references2 array of included plugins or features
+ * @return change with the highest priority from <code>references2</code> to <code>references1</code>
+ * @throws CoreException <p>if any nested CoreException has been thrown</p>
+ */
+ private int compareReferences(String parentID, Object[] references1, Object[] references2, IProgressMonitor monitor) throws CoreException {
+ try {
+ // generate Maps for references1 and references2
+ Map referenceMap1 = generateTable(references1);
+ Map referenceMap2 = generateTable(references2);
+ //
+ if (referenceMap1 == null && referenceMap2 == null) {
+ return IVersionCompare.NO_CHANGE;
+ }
+ monitor.beginTask(Messages.FeatureVersionCompare_comparingReferenceMsg, referenceMap1 == null? 1 : referenceMap1.size() + 1);
+ // initialization before compare
+ int overallChange = IVersionCompare.NO_CHANGE;
+ if (referenceMap1 != null) {
+ // compares features(or plugin entries) in referenceMap1 to those in referenceMap2
+ for (Iterator keys = referenceMap1.keySet().iterator(); keys.hasNext();) {
+ if (monitorWrapper.isCanceled())
+ throw new OperationCanceledException();
+ // get the next key (feature id)
+ Object id = keys.next();
+ // get corresponding version from referenceMap1
+ Version version1 = referenceMap1 == null ? null : (Version) (referenceMap1.get(id));
+ // get the version of corresponding reference from referenceMap2
+ Version version2 = referenceMap2 == null ? null : (Version) referenceMap2.get(id);
+ int currentChange = IVersionCompare.NO_CHANGE;
+ if (references1[0] instanceof IIncludedFeatureReference) {
+ currentChange = compareIncludedFeatureReference(parentID, (String) id, version1, version2, new SubProgressMonitor(monitor, 1));
+ } else {
+ currentChange = compareIncludedPluginReference(parentID, (String) id, version1, version2, new SubProgressMonitor(monitor, 1));
+ }
+ // we save the version change with higher priority
+ overallChange = Math.min(overallChange, currentChange);
+ // delete the reference from referenceMap2
+ if (referenceMap2 != null)
+ referenceMap2.remove(id);
+ }
+ }
+ // new features or plugins added into the feature
+ if (referenceMap2 != null) {
+ for (Iterator keys = referenceMap2.keySet().iterator(); keys.hasNext();) {
+ Object id = keys.next();
+ Version version = (Version) referenceMap2.get(id);
+ if (references2[0] instanceof IIncludedFeatureReference) {
+ Object[] msg = {FEATURE_TITLE, (String) id + UNDERSCORE_MARK + version.toString(), parentID, featureModelTable1.getVersion(parentID), featureModelTable1.getLocation(parentID)};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_deletedFeaturePluginMsg, msg), null));
+ } else {
+ Object[] msg = {PLUGIN_TITLE, (String) id + UNDERSCORE_MARK + version.toString(), parentID, featureModelTable1.getVersion(parentID), featureModelTable1.getLocation(parentID)};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_deletedFeaturePluginMsg, msg), null));
+ }
+ }
+ if (!referenceMap2.isEmpty()) {
+ overallChange = Math.min(overallChange, IVersionCompare.NO_LONGER_EXIST);
+ }
+ }
+ monitor.worked(1);
+ return overallChange;
+ } finally {
+ monitor.done();
+ }
+ }
+
+ /**
+ * compares two versions of an included plugins
+ * @param parentID ID of the feature to which the plugin denoted by <code>pluginID</code> belongs
+ * @param pluginID plugin id
+ * @param version1 new version of plugin denoted by <code>pluginID</code>
+ * @param version2 old version of plugin denoted by <code>pluginID</code>
+ * @return change happened on plugin denoted by <code>pluginID</code>
+ */
+ private int compareIncludedPluginReference(String parentID, String pluginID, Version version1, Version version2, IProgressMonitor monitor) {
+ try {
+ monitor.beginTask("", 10); //$NON-NLS-1$
+ int pluginChange = IVersionCompare.NO_CHANGE;
+ if (version2 == null) {
+ // if version2 is null, the plugin is a new added one
+ Object[] msg = {PLUGIN_TITLE, pluginID + UNDERSCORE_MARK + version1.toString(), parentID, featureModelTable1.getVersion(parentID), featureModelTable1.getLocation(parentID)};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_newAddedFeaturePlingMsg, msg), null));
+ //pluginChange = IVersionCompare.NEW_ADDED;
+ // the return was changed to a MINOR_CHANGE because adding a new plugin is considering a minor change
+ // and the value associated with NEW_ADDED indicates that it is a greater than minor change
+ pluginChange = IVersionCompare.MINOR_CHANGE;
+ } else {
+ if (version1.compareTo(version2) < 0) {
+ // if version1 is lower than version2, it is wrong
+ Object[] msg = new Object[] {version1, PLUGIN_TITLE, pluginID, parentID, featureModelTable1.getVersion(parentID), featureModelTable1.getLocation(parentID), version2, featureModelTable2.getVersion(parentID), featureModelTable1.getLocation(parentID)};
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_lowerNewVersion, msg), null));
+ if (!needPluginCompare)
+ return IVersionCompare.ERROR_OCCURRED;
+ }
+ if (needPluginCompare) {
+ // Object level compare
+ String pluginKey1 = pluginID + KEY_SEPARATOR + version1.toString();
+ String pluginKey2 = pluginID + KEY_SEPARATOR + version2.toString();
+ // check if the plugin has been compared
+ CheckedItem pluginResult = searchPluginResult(pluginKey1 + pluginKey2);
+ monitor.worked(1);
+ if (pluginResult != null) {
+ pluginChange = pluginResult.getChange();
+ } else {
+ // compare plugins as objects
+ IPath pluginDirPath1 = getPluginDirPath(featureModelTable1.getLocation(parentID));
+ IPath pluginDirPath2 = getPluginDirPath(featureModelTable2.getLocation(parentID));
+ Map pluginInfo1 = searchPlugin(pluginDirPath1, pluginID, version1.toString());
+ Map pluginInfo2 = searchPlugin(pluginDirPath2, pluginID, version2.toString());
+ monitor.worked(2);
+ // do plugin compare if both pluginPath1 and pluginPath2 are not null
+ if (pluginInfo1 != null && pluginInfo2 != null) {
+ try {
+ // compare two plugins
+ pluginChange = Math.min(pluginChange, pluginVersionCompare.checkPluginVersions(finalResult, ((IPath) pluginInfo1.get(BUNDLE_LOCATION)).toFile(), (ManifestElement[]) pluginInfo1.get(BUNDLE_CLASSPATH), ((IPath) pluginInfo2.get(BUNDLE_LOCATION)).toFile(), (ManifestElement[]) pluginInfo2.get(BUNDLE_CLASSPATH), new SubProgressMonitor(monitor, 7)));
+ } catch (CoreException ce) {
+ pluginChange = IVersionCompare.ERROR_OCCURRED;
+ }
+ if (pluginChange == IVersionCompare.ERROR_OCCURRED) {
+ // put the compare result into table, we don't need to compare it again if it is also included in another feature
+ pluginProcessed(new CheckedItem(pluginKey1, pluginKey2, null, pluginChange));
+ // set message
+ Object[] msg = {pluginID + UNDERSCORE_MARK + version1.toString(), parentID, featureModelTable1.getVersion(parentID), featureModelTable1.getLocation(parentID)};
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_errorInVerifyPluginMsg, msg), null));
+ // if result is error, set overallChange as error and continue to check next plugin
+ pluginChange = IVersionCompare.ERROR_OCCURRED;
+ } else {
+ // get recommended version based on compare result
+ Version recommendedVersion = recommendVersion(version2, pluginChange);
+ if (!isNewVersionValid(version1, recommendedVersion, pluginChange)) {
+ // if version1 is not correct, set message
+ Object[] msg = {pluginID, version1.toString(), ((IPath) pluginInfo1.get(BUNDLE_LOCATION)).toOSString(), recommendedVersion};
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_incorrectPluginVersionMsg, msg), null));
+ }else{
+ // check if version has been increased properly
+ int actualChange = checkVersionChange(version1, version2);
+ if (actualChange < pluginChange){
+ Object[] msg = new Object[] {pluginID, version1, getVersionName(pluginChange), getVersionName(actualChange)};
+ finalResult.merge(resultStatusHandler(IStatus.WARNING, IVersionCompare.FEATURE_OVERALL_STATUS, NLS.bind(Messages.FeatureVersionCompare_incorrectPluginVersionChange, msg), null));
+ pluginChange = actualChange;
+ }
+ }
+ // put the compare result into table, we don't need to compare it again if it is also included in another feature
+ pluginProcessed(new CheckedItem(pluginKey1, pluginKey2,recommendedVersion, pluginChange));
+ }
+ } else {
+ // if pluginPath1 or pluginPath2 is null, set messages
+ if (pluginInfo1 == null) {
+ Object[] msg = {pluginID + UNDERSCORE_MARK + version1.toString(), parentID, featureModelTable1.getVersion(parentID), featureModelTable1.getLocation(parentID), pluginDirPath1};
+ finalResult.merge(resultStatusHandler(IStatus.WARNING, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_pluginNotFoundMsg, msg), null));
+ }
+ if (pluginInfo2 == null) {
+ Object[] msg = {pluginID + UNDERSCORE_MARK + version2.toString(), parentID, featureModelTable2.getVersion(parentID), featureModelTable2.getLocation(parentID), pluginDirPath2};
+ finalResult.merge(resultStatusHandler(IStatus.WARNING, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_pluginNotFoundMsg, msg), null));
+ }
+ pluginChange = IVersionCompare.ERROR_OCCURRED;
+ // put the compare into table, we don't need to compare it again if it is also included in another feature
+ pluginProcessed(new CheckedItem(pluginKey1, pluginKey2, null, pluginChange));
+ }
+ }
+ } else {
+ // String level compare
+ pluginChange = checkVersionChange(version1, version2);
+ }
+ }
+ return pluginChange;
+ } finally {
+ monitor.done();
+ }
+ }
+
+ /**
+ * compares two versions of an included features
+ * @param parentID ID of the feature to which the feature denoted by <code>featureID</code> belongs
+ * @param featureID feature id
+ * @param version1 new version of feature denoted by <code>featureID</code>
+ * @param version2 old version of feature denoted by <code>featureID</code>
+ * @return change happened on feature denoted by <code>featureID</code>
+ * @throws CoreException <p>if any nested CoreException has been thrown</p>
+ */
+ private int compareIncludedFeatureReference(String parentID, String featureID, Version version1, Version version2, IProgressMonitor monitor) throws CoreException {
+ String key1 = featureID + KEY_SEPARATOR + version1.toString();
+ int change = IVersionCompare.NO_CHANGE;
+ // if version2 is null, the feature is a new added one
+ if (version2 == null) {
+ Object[] msg = {FEATURE_TITLE, featureID + UNDERSCORE_MARK + version1.toString(), parentID, featureModelTable1.getVersion(parentID), featureModelTable1.getLocation(parentID)};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_newAddedFeaturePlingMsg, msg), null));
+ change = IVersionCompare.NEW_ADDED;
+ }
+ // get the corresponding FeatureModel from featureModelTable1
+ FeatureModel featureModel1 = (FeatureModel) featureModelTable1.getFeatureModel(featureID);
+ FeatureModel featureModel2 = (FeatureModel) featureModelTable2.getFeatureModel(featureID);
+ if (featureModel1 == null) {
+ // if the new FeatureModel has not been found, it's an error
+ Object[] msg = {featureID + UNDERSCORE_MARK + version1.toString(), parentID, featureModelTable1.getVersion(parentID), featureModelTable1.getLocation(parentID)};
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_sourceIncludedFeatureNotFoundMsg, msg), null));
+ change = IVersionCompare.ERROR_OCCURRED;
+ } else if (!featureModel1.getFeatureVersion().equals(version1.toString())) {
+ //if the version of the FeatureModel we got does not match the version of the reference, it is an error
+ // e.g. feature f1 includes feature f2-1.0.0.v2006, but the corresponding FeatureModel we found is feature f2-1.0.1, it is wrong
+ Object[] msg = {featureID + UNDERSCORE_MARK + version1.toString(), parentID, featureModelTable1.getVersion(parentID), featureModelTable1.getLocation(parentID)};
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_sourceIncludedFeatureNotFoundMsg, msg), null));
+ change = IVersionCompare.ERROR_OCCURRED;
+ }
+ // if the feature is a new added one, we don't do further check
+ if (version2 != null) {
+ if (featureModel2 == null) {
+ // if featureModel2 is null, it is an error
+ Object[] msg = {featureID + UNDERSCORE_MARK + version2.toString(), parentID, featureModelTable2.getVersion(parentID), featureModelTable2.getLocation(parentID)};
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_destIncludedFeatureNotFoundMsg, msg), null));
+ change = IVersionCompare.ERROR_OCCURRED;
+ } else if (!featureModel2.getFeatureVersion().equals(version2.toString())) {
+ //if the version of the FeatureModel we got does not match the version of the reference, it is an error
+ // e.g. feature f1 includes feature f2-1.0.0.v2006, but the corresponding FeatureModel we found is feature f2-1.0.1, it is wrong
+ Object[] msg = {featureID + UNDERSCORE_MARK + version2.toString(), parentID, featureModelTable2.getVersion(parentID), featureModelTable2.getLocation(parentID)};
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_destIncludedFeatureNotFoundMsg, msg), null));
+ change = IVersionCompare.ERROR_OCCURRED;
+ }
+ // String level compare
+ if (version1.compareTo(version2) < 0) {
+ Object[] msg = new Object[] {version1, FEATURE_TITLE, featureID, parentID, featureModelTable1.getVersion(parentID), featureModelTable1.getLocation(parentID), version2, featureModelTable2.getVersion(parentID), featureModelTable1.getLocation(parentID)};
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.FEATURE_DETAIL_STATUS, NLS.bind(Messages.FeatureVersionCompare_lowerNewVersion, msg), null));
+ }
+ if (change == IVersionCompare.ERROR_OCCURRED) {
+ featureProcessed(new CheckedItem(key1, null, null, IVersionCompare.ERROR_OCCURRED));
+ return IVersionCompare.ERROR_OCCURRED;
+ }
+ // check if the current feature version has been checked
+ CheckedItem compareResult = searchFeatureResult(key1);
+ // Object level compare
+ if (compareResult == null) {
+ // check the included feature models and get result status
+ compareResult = verifyNewFeatureVersion(featureModel1, featureModel2, monitorWrapper.getSubMonitor(needPluginCompare ? 90 : 40 / featureModelTable1.size()));
+ // add the result status into result list
+ featureProcessed(compareResult);
+ }
+ change = Math.min(change, compareResult.getChange());
+ }
+ return change;
+ }
+
+ /*
+ * Return a Map contains bundle name, bundle version, bundle classpath, and bundle location
+ * if the location of the specific plug-in version that we are looking for. Otherwise return
+ * <code>null</code>
+ */
+ private Map matchesPlugin(File file, String pluginName, String pluginVersion) throws CoreException {
+ if (!file.exists())
+ return null;
+ Map manifest = ManifestHelper.getElementsFromManifest(file, new String[] {BUNDLE_SYMBOLICNAME, BUNDLE_VERSION, BUNDLE_CLASSPATH});
+ ManifestElement[] elements = (ManifestElement[]) manifest.get(BUNDLE_SYMBOLICNAME);
+ if (elements == null)
+ return null;
+ String name = elements[0].getValue();
+ if (name == null || !name.equals(pluginName))
+ return null;
+ elements = (ManifestElement[]) manifest.get(BUNDLE_VERSION);
+ if (elements == null)
+ return null;
+ String version = elements[0].getValue();
+ if (version == null || !version.equals(pluginVersion))
+ return null;
+ manifest.put(BUNDLE_LOCATION, new Path(file.getAbsolutePath()));
+ return manifest;
+ }
+
+ /**
+ * searches for plugin denoted by <code>pluginName</code> and <code>pluginVersion</code> under
+ * plugin directory indicated by <code>plugDir</code>, and return a Map contains bundle name,
+ * bundle version, bundle classpath, and bundle location if we find, return <code>null</code>
+ * if we don't find
+ *
+ * @param plugDir plugin directory
+ * @param pluginName plugin name
+ * @param pluginVersion plugin version
+ * @return full path of plugin
+ */
+ private Map searchPlugin(IPath plugDir, String pluginName, String pluginVersion) {
+ // as an optimization first check to see if the plug-in directory name is the Eclipse-format
+ try {
+ // check to see if we can guess the JAR name
+ File jar = plugDir.append(pluginName + UNDERSCORE_MARK + pluginVersion + DOT_MARK + JAR_FILE_EXTENSION).toFile();
+ Map manifest = matchesPlugin(jar, pluginName, pluginVersion);
+ if (manifest != null)
+ return manifest;
+ // didn't match the JAR so try and match the directory name
+ File dir = plugDir.append(pluginName + UNDERSCORE_MARK + pluginVersion).toFile();
+ manifest = matchesPlugin(dir, pluginName, pluginVersion);
+ if (manifest != null)
+ return manifest;
+ } catch (CoreException e) {
+ // ignore and catch below if re-thrown
+ }
+ File[] plugins = plugDir.toFile().listFiles();
+ if (plugins == null)
+ return null;
+ for (int i = 0; i < plugins.length; i++) {
+ try {
+ Map manifest = matchesPlugin(plugins[i], pluginName, pluginVersion);
+ if (manifest != null)
+ return manifest;
+ } catch (CoreException ce) {
+ finalResult.merge(resultStatusHandler(IStatus.WARNING, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.PluginVersionCompare_couldNotReadManifestMsg, plugins[i].getAbsolutePath()), null));
+ }
+ }
+ return null;
+ }
+
+ /**
+ * generates a map which stores the key-value pairs; Feature id(or plugin id) is key and version is value;
+ * or <code>null</code> when <code>objects</code> is empty
+ *
+ * @param objects array of feature or plugin entry objects
+ * @return Map instance contains id-version pairs or <code>null</code>
+ * @throws CoreException <p>if any nested CoreException has been thrown</p>
+ */
+ private Map generateTable(Object[] objects) throws CoreException {
+ if (objects == null || objects.length == 0) {
+ return null;
+ }
+ Hashtable hashTable = new Hashtable();
+ // set the ids and versions of plugins into hashtable, id is key, version is value
+ if (objects[0] instanceof IIncludedFeatureReference) {
+ for (int i = 0; i < objects.length; i++)
+ if (objects[i] != null && (compareOptionFileHelper == null ? true : compareOptionFileHelper.shouldCompare(objects[i])))
+ hashTable.put(((IIncludedFeatureReference) objects[i]).getVersionedIdentifier().getIdentifier(), new Version(((IIncludedFeatureReference) objects[i]).getVersionedIdentifier().getVersion().toString()));
+ } else if (objects[0] instanceof PluginEntryModel) {
+ for (int i = 0; i < objects.length; i++)
+ if (objects[i] != null && (compareOptionFileHelper == null ? true : compareOptionFileHelper.shouldCompare(objects[i])))
+ hashTable.put(((PluginEntryModel) objects[i]).getPluginIdentifier(), new Version(((PluginEntryModel) objects[i]).getPluginVersion()));
+ }
+ return hashTable;
+ }
+
+ /**
+ * Checks if there is any change from <version2> to <version1>
+ *
+ * @param version1 feature version
+ * @param version2 feature version
+ * @return compare result indicates change in major, minor, micro, qualifier ,no change or error if <code>version1</code> is lower than <code>version2</code>
+ */
+ private int checkVersionChange(Version version1, Version version2) {
+ // overall compare
+ if (version1.compareTo(version2) < 0) {
+ return IVersionCompare.ERROR_OCCURRED;
+ }
+ // compare major version
+ if (version1.getMajor() > version2.getMajor()) {
+ return IVersionCompare.MAJOR_CHANGE;
+ }
+ // compare minor version
+ if (version1.getMinor() > version2.getMinor()) {
+ return IVersionCompare.MINOR_CHANGE;
+ }
+ // compare micro version
+ if (version1.getMicro() > version2.getMicro()) {
+ return IVersionCompare.MICRO_CHANGE;
+ }
+ // compare qualifier version
+ if (version1.getQualifier().compareTo(version2.getQualifier()) > 0) {
+ return IVersionCompare.QUALIFIER_CHANGE;
+ }
+ // if we got to this point, it means no change
+ return IVersionCompare.NO_CHANGE;
+ }
+
+ /**
+ * Returns the compare result for the feature with the specified key. Returns <code>null</code>
+ * if it is not found.
+ *
+ * @param key FeatureKey instance (feature id + "#" + feature version)
+ * @return the compare result or <code>null</code>
+ */
+ private CheckedItem searchFeatureResult(Object key) {
+ return (CheckedItem) verifiedFeatureTable.get(key);
+ }
+
+ /**
+ * Returns the compare result for the plugin with the specified key. Returns <code>null</code>
+ * if it is not found.
+ *
+ * @param key compare source plugin key instance (plugin id + "#" + plugin version) + "#" +
+ * compare destination plugin key instance (plugin id + "#" + plugin version)
+ * @return the compare result or <code>null</code> if not found
+ */
+ private CheckedItem searchPluginResult(Object key) {
+ return (CheckedItem) verifiedPluginTable.get(key);
+ }
+
+ /**
+ * Return a new status object populated with the given information.
+ *
+ * @param severity severity of status
+ * @param code indicates type of this IStatus instance, it could be one of: FEATURE_OVERALL_STATUS,
+ * FEATURE_DETAIL_STATUS, PLUGIN_OVERALL_STATUS, PLUGIN_DETAIL_STATUS, PROCESS_ERROR_STATUS,
+ * CLASS_OVERALL_STATUS, CLASS_DETAIL_STATUS
+ * @param message the status message
+ * @param exception exception which has been caught, or <code>null</code>
+ * @return the new status object
+ */
+ private IStatus resultStatusHandler(int severity, int code, String message, Exception exception) {
+ if (message == null) {
+ if (exception != null)
+ message = exception.getMessage();
+ // extra check because the exception message can be null
+ if (message == null)
+ message = EMPTY_STRING;
+ }
+ return new Status(severity, PLUGIN_ID, code, message, exception);
+ }
+
+ /**
+ * get path of "plugins/" based on the given feature file path
+ * @param featurePath path of a "feature.xml" file
+ * @return path of "plugins/"
+ */
+ private IPath getPluginDirPath(IPath featurePath) {
+ IPath path = featurePath.removeLastSegments(3);
+ return path.append(PLUGIN_DIR_NAME);
+ }
+} \ No newline at end of file
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/JavaClassVersionCompare.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/JavaClassVersionCompare.java
new file mode 100755
index 000000000..26a7fd9ff
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/JavaClassVersionCompare.java
@@ -0,0 +1,654 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import java.io.InputStream;
+import java.util.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.util.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.pde.tools.versioning.IVersionCompare;
+
+/**
+ * ClassSourceVersionCompare
+ */
+public class JavaClassVersionCompare implements VersionCompareConstants {
+ // MultiStatus instance used to store IStatus objects which indicate changes between two java classes
+ private MultiStatus finalResult;
+ //
+ private boolean hasMajorChange;
+ private boolean hasMinorChange;
+ private boolean hasMicroChange;
+ private boolean hasError;
+
+ /**
+ * Constructor
+ */
+ public JavaClassVersionCompare() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.internal.versioning.VersionCompareDispatcher#checkJavaClassVersions(String, String, IProgressMonitor)
+ */
+ public int checkJavaClassVersions(MultiStatus status, Object javaClassObj1, Object javaClassObj2, IProgressMonitor monitor) throws CoreException {
+ try {
+ monitor = VersioningProgressMonitorWrapper.monitorFor(monitor);
+ monitor.beginTask(Messages.JavaClassVersionCompare_comparingClassMsg, 100);
+ finalResult = status;
+ // get IClassFileReader instances of javaClassObj1 and javaClassObj2
+ IClassFileReader classFileReader1 = ClassFileHelper.getReader(javaClassObj1);
+ if (classFileReader1 == null) {
+ if (javaClassObj1 instanceof InputStream)
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, Messages.JavaClassVersionCompare_inputStreamErrMsg, null));
+ else
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.JavaClassVersionCompare_classFileNotLoadedMsg, javaClassObj1), null));
+ return IVersionCompare.ERROR_OCCURRED;
+ }
+ IClassFileReader classFileReader2 = ClassFileHelper.getReader(javaClassObj2);
+ // worked 5%
+ monitor.worked(5);
+ if (monitor.isCanceled())
+ throw new OperationCanceledException();
+ if (classFileReader2 == null) {
+ if (javaClassObj2 instanceof InputStream)
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, Messages.JavaClassVersionCompare_inputStreamErrMsg, null));
+ else
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.JavaClassVersionCompare_classFileNotLoadedMsg, javaClassObj2), null));
+ return IVersionCompare.ERROR_OCCURRED;
+ }
+ // worked 5%
+ monitor.worked(5);
+ if (monitor.isCanceled())
+ throw new OperationCanceledException();
+ // initialize flags
+ hasError = false;
+ hasMajorChange = false;
+ hasMinorChange = false;
+ hasMicroChange = false;
+ // compare two classes ( 90% workload)
+ compareJavaClasses(classFileReader1, classFileReader2, new SubProgressMonitor(monitor, 90));
+ // analysis result
+ if (hasError) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.CLASS_OVERALL_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.JavaClassVersionCompare_classErrorOccurredMsg, charsToString(classFileReader1.getClassName())), null));
+ return IVersionCompare.ERROR_OCCURRED;
+ }
+ if (hasMajorChange) {
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_OVERALL_STATUS, NLS.bind(Messages.JavaClassVersionCompare_classMajorChangeMsg, charsToString(classFileReader1.getClassName())), null));
+ return IVersionCompare.MAJOR_CHANGE;
+ }
+ if (hasMinorChange) {
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_OVERALL_STATUS, NLS.bind(Messages.JavaClassVersionCompare_classMinorChangeMsg, charsToString(classFileReader1.getClassName())), null));
+ return IVersionCompare.MINOR_CHANGE;
+ }
+ if (hasMicroChange) {
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_OVERALL_STATUS, NLS.bind(Messages.JavaClassVersionCompare_classMicroChange, charsToString(classFileReader1.getClassName())), null));
+ return IVersionCompare.MICRO_CHANGE;
+ }
+ return IVersionCompare.NO_CHANGE;
+ } finally {
+ monitor.done();
+ }
+ }
+
+ /**
+ * compares two java classes denoted by <code>classFileReader1</code> and <code>classFileReader2</code>,
+ * and check if there is any change from <code>classFileReader2</code> to <code>classFileReader1</code>.
+ *
+ * @param classFileReader1
+ * @param classFileReader2
+ * @param monitor IProgressMonitor instance
+ * @return compare result IStatus instance
+ */
+ private IStatus compareJavaClasses(IClassFileReader classFileReader1, IClassFileReader classFileReader2, IProgressMonitor monitor) {
+ try {
+ monitor.beginTask("", 100); //$NON-NLS-1$
+ // compare class names
+ String name1 = charsToString(classFileReader1.getClassName());
+ String name2 = charsToString(classFileReader2.getClassName());
+ if (!name1.equals(name2)) {
+ finalResult.merge(resultStatusHandler(IStatus.WARNING, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.JavaClassVersionCompare_differentClassNameMsg, name1, name2), null));
+ return finalResult;
+ }
+ // worked 5%
+ monitor.worked(5);
+ // compare super classes
+ checkSuperClasses(name1, classFileReader1.getSuperclassName(), classFileReader2.getSuperclassName());
+ // worked 5%
+ monitor.worked(5);
+ // compare interfaces
+ checkInterfaces(name1, generateList(classFileReader1.getInterfaceNames()), generateList(classFileReader2.getInterfaceNames()));
+ // worked 5%
+ monitor.worked(5);
+ // compare modifier of classes
+ checkClassModifiers(name1, classFileReader1.getAccessFlags(), classFileReader2.getAccessFlags());
+ // worked 5%
+ monitor.worked(5);
+ // compare fields
+ checkElements(name1, generateTable(classFileReader1.getFieldInfos()), generateTable(classFileReader2.getFieldInfos()));
+ // worked 40%
+ monitor.worked(40);
+ // compare methods (40%)
+ checkElements(name1, generateTable(classFileReader1.getMethodInfos()), generateTable(classFileReader2.getMethodInfos()));
+ return finalResult;
+ } finally {
+ monitor.done();
+ }
+ }
+
+ /**
+ * checks if super class has been changed
+ *
+ * @param className name of the class we are comparing
+ * @param superClassName1
+ * @param superClassName2
+ */
+ private void checkSuperClasses(String className, char[] superClassName1, char[] superClassName2) {
+ if (!charsToString(superClassName1).equals(charsToString(superClassName2))) {
+ Object[] msg = {className, charsToString(superClassName2), charsToString(superClassName1)};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_differentSuperClassMsg, msg), null));
+ }
+ }
+
+ /**
+ * checks if there is any change between <code>interfaceList1</code> and <code>interfaceList2</code>
+ *
+ * @param className name of the class we are comparing
+ * @param interfaceList1 List of interface name
+ * @param interfaceList2 List of interface name
+ */
+ private void checkInterfaces(String className, List interfaceList1, List interfaceList2) {
+ for (Iterator nameIterator1 = interfaceList1.iterator(); nameIterator1.hasNext();) {
+ // get a name of interface from interfaceNames1
+ String name1 = (String) nameIterator1.next();
+ // check if the interface is in interfaceNames2
+ if (!interfaceList2.remove(name1))
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_newAddedInterfaceMsg, name1, className), null));
+ }
+ // check what does no longer exist
+ for (Iterator nameIterator2 = interfaceList2.iterator(); nameIterator2.hasNext();) {
+ String name2 = (String) nameIterator2.next();
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_deletedInterfaceMsg, name2, className), null));
+ }
+ }
+
+ /**
+ * checks two class modifiers to see if there is any change from <code>accessFlag2</code> to <code>accessFlag1</code>
+ * @param accessFlag1
+ * @param accessFlag2
+ */
+ private void checkClassModifiers(String className, int accessFlag1, int accessFlag2) {
+ int change = accessFlag1 ^ accessFlag2;
+ if (change != 0) {
+ // if the visibility of a method has been narrowed, it is a change should be caught
+ Object[] msg = {className, createChangedModifierString(accessFlag2, change), createChangedModifierString(accessFlag1, change)};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_classModifierChangedMsg, msg), null));
+ }
+ }
+
+ /**
+ * checks corresponding elements(IMethodInfo instances or IFieldInfo instances),
+ * to see if there is any change
+ * @param className className name of class to which values in <code>elementMap1</code>
+ * (and <code>elementMap2</code>) belong
+ * @param elementMap1 map contains IMethodInfo instances or IFieldInfo instances
+ * @param elementMap2 map contains IMethodInfo instances or IFieldInfo instances
+ */
+ private void checkElements(String className, Map elementMap1, Map elementMap2) {
+ for (Iterator iterator1 = elementMap1.keySet().iterator(); iterator1.hasNext();) {
+ // get a key and value from methodMap1
+ String key = (String) iterator1.next();
+ Object value1 = elementMap1.get(key);
+ // try to get the corresponding method from methodMap2
+ Object value2 = elementMap2.get(key);
+ if (value2 != null) {
+ if (value1 instanceof IMethodInfo)
+ // compare the corresponding methods
+ compareMethodInfos(className, (IMethodInfo) value1, (IMethodInfo) value2);
+ else
+ // compare the corresponding fields in fieldInfoMap1 and fieldInfoMap2
+ compareFieldInfos(className, (IFieldInfo) value1, (IFieldInfo) value2);
+ elementMap2.remove(key);
+ } else {
+ if (value1 instanceof IMethodInfo) {
+ if (Flags.isPublic(((IMethodInfo) value1).getAccessFlags()) || Flags.isProtected(((IMethodInfo) value1).getAccessFlags())) {
+ Object[] msg = new Object[] {METHOD_TITLE, getSignatureString(value1), className};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MINOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_newAddedMsg, msg), null));
+ }
+ } else {
+ if (Flags.isPublic(((IFieldInfo) value1).getAccessFlags()) || Flags.isProtected(((IFieldInfo) value1).getAccessFlags())) {
+ Object[] msg = new Object[] {FIELD_TITLE, getSignatureString(value1), className};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MINOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_newAddedMsg, msg), null));
+ }
+ }
+ }
+ }
+ // if there are anythings left in fieldInfoMap1, they no longer exist in the class
+ for (Iterator iterator2 = elementMap2.values().iterator(); iterator2.hasNext();) {
+ Object object = iterator2.next();
+ if (object instanceof IMethodInfo) {
+ // we only care which is protected or public
+ if (Flags.isPublic(((IMethodInfo) object).getAccessFlags()) || Flags.isProtected(((IMethodInfo) object).getAccessFlags())) {
+ Object[] msg = new Object[] {METHOD_TITLE, getSignatureString(object), className};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_noLongerExistMsg, msg), null));
+ }
+ } else {
+ if (Flags.isPublic(((IFieldInfo) object).getAccessFlags()) || Flags.isProtected(((IFieldInfo) object).getAccessFlags())) {
+ Object[] msg = new Object[] {FIELD_TITLE, getSignatureString(object), className};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_noLongerExistMsg, msg), null));
+ }
+ }
+
+ }
+ }
+
+ /**
+ * compares two IMethodInfo instances to find any change from <code>method2</code> to <code>method1</code>
+ *
+ * @param className name of class to which <code>method1</code>(and <code>method2</code>) belongs
+ * @param method1 IMethodInfo instance
+ * @param method2 IMethodInfo instance
+ */
+ private void compareMethodInfos(String className, IMethodInfo method1, IMethodInfo method2) {
+ // compare AccessFlags (AccessFlags defines the modifiers of a method (e.g. public static final compareTo())
+ int accessFlag1 = method1.getAccessFlags();
+ int accessFlag2 = method2.getAccessFlags();
+ // we just care about field who was public or protected
+ if (!(Flags.isPublic(accessFlag2) || Flags.isProtected(accessFlag2)))
+ return;
+ if (isModifierNarrowed(accessFlag1, accessFlag2)) {
+ // get what modifiers have been changed
+ int change = accessFlag1 ^ accessFlag2;
+ // if the visibility of a method has been narrowed, it is a change should be caught
+ Object[] msg = {METHOD_TITLE, getSignatureString(method1), createChangedModifierString(accessFlag2, change), createChangedModifierString(accessFlag1, change), className};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_ModifierChangedMsg, msg), null));
+ }
+ // compare isDeprecated(if a method has been deprecated)
+ if (method1.isDeprecated() && !method2.isDeprecated()) {
+ Object[] msg = {METHOD_TITLE, getSignatureString(method1), className};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MICRO_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_deprecatedChangedMsg, msg), null));
+ }
+ // compare exceptions
+ IExceptionAttribute exceptionAtrributes1 = method1.getExceptionAttribute();
+ IExceptionAttribute exceptionAtrributes2 = method2.getExceptionAttribute();
+ checkExceptions(className, getSignatureString(method1), exceptionAtrributes1, exceptionAtrributes2);
+ }
+
+ /**
+ * check two IExceptionAttribute instances to see if there is any change
+ * @param className name of the class to which the method denoted by <code>methodName</code> belongs
+ * @param methodName name of the method to which exceptionsAttribute1(exceptionsAttribute2) belongs
+ * @param exceptionsAttribute1
+ * @param exceptionsAttribute2
+ */
+ private void checkExceptions(String className, String methodName, IExceptionAttribute exceptionsAttribute1, IExceptionAttribute exceptionsAttribute2) {
+ List exceptionList1 = null;
+ List exceptionList2 = null;
+ if (exceptionsAttribute1 != null && exceptionsAttribute2 != null) {
+ exceptionList1 = generateList(exceptionsAttribute1.getExceptionNames());
+ exceptionList2 = generateList(exceptionsAttribute2.getExceptionNames());
+ } else if (exceptionsAttribute1 != null) {
+ exceptionList1 = generateList(exceptionsAttribute1.getExceptionNames());
+ } else if (exceptionsAttribute2 != null) {
+ exceptionList2 = generateList(exceptionsAttribute2.getExceptionNames());
+ } else {
+ return;
+ }
+ StringBuffer newAddedExceptions = new StringBuffer();
+ if (exceptionList1 != null) {
+ // check what is new added
+ for (Iterator iterator1 = exceptionList1.iterator(); iterator1.hasNext();) {
+ // get a exception from exceptionList1
+ String exception1 = (String) iterator1.next();
+ if (exceptionList2 != null) {
+ // check if the exception is in exceptionList2
+ if (!exceptionList2.remove(exception1)) {
+ newAddedExceptions.append(exception1);
+ newAddedExceptions.append(COMMA_MARK);
+ }
+ } else {
+ // if exceptionList2 is null, it is new added
+ newAddedExceptions.append(exception1);
+ newAddedExceptions.append(COMMA_MARK);
+ }
+ }
+ if (!newAddedExceptions.toString().trim().equals(EMPTY_STRING)) {
+ Object[] msg = {newAddedExceptions.toString(), methodName, className};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MINOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_newAddedExceptionMsg, msg), null));
+ }
+ }
+ if (exceptionList2 != null) {
+ StringBuffer notExistExceptions = new StringBuffer();
+ // check what does no longer exist
+ for (Iterator iterator2 = exceptionList2.iterator(); iterator2.hasNext();) {
+ String exception2 = (String) iterator2.next();
+ notExistExceptions.append(exception2);
+ notExistExceptions.append(COMMA_MARK);
+ }
+ if (!notExistExceptions.toString().trim().equals(EMPTY_STRING)) {
+ Object[] msg2 = {notExistExceptions.toString(), methodName, className};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MINOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_noLongerExistExceptionMsg, msg2), null));
+ }
+ }
+ }
+
+ /**
+ * checks if there is any change from <code>accessFlag2</code> to <code>accessFlag1</code>
+ * we check changes which narrowed down the visibility of a field or method with protected or public modifier
+ *
+ * @param accessFlag1 denotes combined modifiers of a field or method
+ * @param accessFlag2 denotes combined modifiers of a field or method
+ * @return <code>true</code> if visibility has been narrowed down from <code>accessFlag2</code> to <code>accessFlag1</code>,
+ * <code>false</code> otherwise
+ */
+ private boolean isModifierNarrowed(int accessFlag1, int accessFlag2) {
+ if (Flags.isProtected(accessFlag2)) {
+ // from protected to modifier other than public and protected
+ if (!(Flags.isPublic(accessFlag1) || Flags.isProtected(accessFlag1))) {
+ return true;
+ }
+ } else if (Flags.isPublic(accessFlag2)) {
+ // from public to modifier other than public
+ if (!Flags.isPublic(accessFlag1)) {
+ return true;
+ }
+ } else {
+ // only check which was protected or public
+ return false;
+ }
+ // from non-final to final
+ if (!Flags.isFinal(accessFlag2) && Flags.isFinal(accessFlag1)) {
+ return true;
+ }
+ // from static to non-static
+ if (Flags.isStatic(accessFlag2) && !Flags.isStatic(accessFlag1)) {
+ return true;
+ }
+ // from non-abstract to abstract
+ if (!Flags.isAbstract(accessFlag2) && Flags.isAbstract(accessFlag1)) {
+ return true;
+ }
+ // volatile modifier changed
+ if (Flags.isVolatile(accessFlag2) != Flags.isVolatile(accessFlag1)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * check if <code>accessFlag</code> is <code>default</code>
+ * @param accessFlag
+ * @return <code>true</code> if <code>addessFlag</code> is <code>default</code>,
+ * <code>false</code> otherwise
+ */
+ private boolean isDefault(int accessFlag) {
+ return (accessFlag & DEFAULT_MODIFIER_TESTER) == 0 ? true : false;
+ }
+
+ /**
+ * compares two IFieldInfo instances to find any change from <code>field1</code> to <code>field2</code>
+ *
+ * @param className name of class to which <code>field1</code>(and <code>field2</code>) belongs
+ * @param field1 IFieldInfo instance
+ * @param field2 IFieldInfo instance
+ */
+ private void compareFieldInfos(String className, IFieldInfo field1, IFieldInfo field2) {
+ // compare AccessFlags (AccessFlags defines the modifiers of a field (e.g. public static final IVersionCompare.PLUGIN_ID = "org.eclipse.pde.tools.versioning")
+ int accessFlag1 = field1.getAccessFlags();
+ int accessFlag2 = field2.getAccessFlags();
+ // we just care about field who was public or protected
+ if (!(Flags.isPublic(accessFlag2) || Flags.isProtected(accessFlag2))) {
+ return;
+ }
+ if (isModifierNarrowed(accessFlag1, accessFlag2)) {
+ // get what modifiers have been changed
+ int change = accessFlag1 ^ accessFlag2;
+ // if the visibility of a field which was public or protected has been narrowed, it is a change should be caught
+ Object[] msg = {FIELD_TITLE, charsToString(field1.getName()), createChangedModifierString(accessFlag2, change), createChangedModifierString(accessFlag1, change), className};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_ModifierChangedMsg, msg), null));
+ }
+ // compare Descriptor (Descriptor describes the type of a field)
+ String descriptor1 = charsToString(field1.getDescriptor());
+ String descriptor2 = charsToString(field2.getDescriptor());
+ if (!descriptor1.equals(descriptor2)) {
+ String[] msg = {charsToString(field1.getName()), Signature.toString(descriptor2), Signature.toString(descriptor1), className};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_descriptorChangedMsg, msg), null));
+ }
+ // compare isDeprecated (if a field has been deprecated)
+ if (field1.isDeprecated() && !field2.isDeprecated()) {
+ Object[] msg = {FIELD_TITLE, charsToString(field1.getName()), className};
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MICRO_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_deprecatedChangedMsg, msg), null));
+ }
+ }
+
+ /**
+ * creates modifier string which includes multiple modifiers(e.g. "public static final")
+ *
+ * @param accessFlags accessFlags of field or method
+ * @param changedFlags indicates change on accessFlags
+ * @return modifier string
+ */
+ private String createChangedModifierString(int accessFlags, int changedFlags) {
+ StringBuffer buffer = new StringBuffer();
+ if (Flags.isPublic(changedFlags)) {
+ if (Flags.isPublic(accessFlags)) {
+ buffer.append(PUBLIC_STRING);
+ buffer.append(SPACE);
+ } else if (isDefault(accessFlags)) {
+ buffer.append(DEFAULT_STRING);
+ buffer.append(SPACE);
+ }
+ }
+ if (Flags.isProtected(changedFlags)) {
+ if (Flags.isProtected(accessFlags)) {
+ buffer.append(PROTECTED_STRING);
+ buffer.append(SPACE);
+ } else if (isDefault(accessFlags)) {
+ buffer.append(DEFAULT_STRING);
+ buffer.append(SPACE);
+ }
+ }
+ if (Flags.isPrivate(changedFlags)) {
+ if (Flags.isPrivate(accessFlags)) {
+ buffer.append(PRIVATE_STRING);
+ buffer.append(SPACE);
+ } else if (isDefault(accessFlags)) {
+ buffer.append(DEFAULT_STRING);
+ buffer.append(SPACE);
+ }
+ }
+ if (Flags.isStatic(changedFlags)) {
+ if (Flags.isStatic(accessFlags)) {
+ buffer.append(STATIC_STRING);
+ buffer.append(SPACE);
+ } else {
+ buffer.append(NON_STATIC_STRING);
+ buffer.append(SPACE);
+ }
+ }
+ if (Flags.isFinal(changedFlags)) {
+ if (Flags.isFinal(accessFlags)) {
+ buffer.append(FINAL_STRING);
+ buffer.append(SPACE);
+ } else {
+ buffer.append(NON_FINAL_STRING);
+ buffer.append(SPACE);
+ }
+ }
+ if (Flags.isAbstract(changedFlags)) {
+ if (Flags.isAbstract(accessFlags)) {
+ buffer.append(ABSTRACT_STRING);
+ buffer.append(SPACE);
+ } else {
+ buffer.append(NON_ABSTRACT_STRING);
+ buffer.append(SPACE);
+ }
+ }
+ if (Flags.isVolatile(changedFlags)) {
+ if (Flags.isVolatile(accessFlags)) {
+ buffer.append(VOLATILE_STRING);
+ buffer.append(SPACE);
+ } else {
+ buffer.append(NON_VOLATILE_STRING);
+ buffer.append(SPACE);
+ }
+ }
+ return buffer.toString().trim();
+ }
+
+ /**
+ * converts char array to String
+ * @param chars array of char
+ * @return String which represents the content of <code>chars</code>
+ */
+ private String charsToString(char[] chars) {
+ return new String(chars);
+ }
+
+ /**
+ * generates a List which stores instances in array <code>objects</code>
+ *
+ * @param objects instance objects
+ * @return List
+ */
+ private List generateList(Object[] objects) {
+ ArrayList list = new ArrayList(0);
+ if (objects == null || objects.length == 0)
+ return list;
+ if (objects[0] instanceof char[])
+ for (int i = 0; i < objects.length; i++)
+ list.add(charsToString((char[]) objects[i]));
+ else
+ for (int i = 0; i < objects.length; i++)
+ list.add(objects[i]);
+ return list;
+ }
+
+ /**
+ * converts the given object signature to a readable string
+ * @param object IFieldInfo instance of IMethodInfo instance
+ * @return String type signature
+ */
+ private String getSignatureString(Object object) {
+ StringBuffer buffer = new StringBuffer();
+ if (object instanceof IMethodInfo) {
+ IMethodInfo method = (IMethodInfo) object;
+ buffer.append(Flags.toString(method.getAccessFlags()));
+ buffer.append(SPACE);
+ buffer.append(Signature.toString(charsToString(method.getDescriptor()), charsToString(method.getName()), null, false, true));
+ } else {
+ IFieldInfo field = (IFieldInfo) object;
+ buffer.append(Flags.toString(field.getAccessFlags()));
+ buffer.append(SPACE);
+ buffer.append(Signature.toString(charsToString(field.getDescriptor())));
+ buffer.append(SPACE);
+ buffer.append(charsToString(field.getName()));
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * generates a map which stores IField instances or IMethod instances
+ *
+ * @param objects array of IMethodInfo or IFieldInfo instances
+ * @return Map instance contains IField instances or IMethod instances
+ */
+ private Map generateTable(Object[] objects) {
+ Hashtable hashTable = new Hashtable(0);
+ if (objects == null || objects.length == 0) {
+ return hashTable;
+ }
+ // set hashtable
+ if (objects[0] instanceof IFieldInfo) {
+ for (int i = 0; i < objects.length; i++) {
+ if (objects[i] != null)
+ hashTable.put(charsToString(((IFieldInfo) objects[i]).getName()), objects[i]);
+ }
+ } else if (objects[0] instanceof IMethodInfo) {
+ for (int i = 0; i < objects.length; i++) {
+ if (objects[i] != null)
+ hashTable.put(getMethodKey((IMethodInfo) objects[i]), objects[i]);
+ }
+ }
+ return hashTable;
+ }
+
+ /**
+ * get key of a method. Key of a method is a String which
+ * includes the retype of the method,name of the method and the parameter types of the method
+ * (e.g. key of public int foo(int , String) is "int#foo#int#String"
+ * @param method
+ * @return key of a method
+ */
+ private String getMethodKey(IMethodInfo method) {
+ StringBuffer buffer = new StringBuffer();
+ // append return type
+ buffer.append(method.getDescriptor());
+ // append name of method
+ buffer.append(charsToString(method.getName()));
+ char[][] parameters = Signature.getParameterTypes(method.getDescriptor());
+ // append parameter types
+ if (parameters != null) {
+ for (int i = 0; i < parameters.length; i++) {
+ buffer.append(KEY_SEPARATOR);
+ buffer.append(charsToString(parameters[i]));
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Return a new status object populated with the given information.
+ *
+ * @param severity severity of status
+ * @param code indicates type of this IStatus instance, it could be one of: FEATURE_OVERALL_STATUS,
+ * FEATURE_DETAIL_STATUS, PLUGIN_OVERALL_STATUS, PLUGIN_DETAIL_STATUS, PROCESS_ERROR_STATUS,
+ * CLASS_OVERALL_STATUS, CLASS_DETAIL_STATUS
+ * @param message the status message
+ * @param exception exception which has been caught, or <code>null</code>
+ * @return the new status object
+ */
+ private IStatus resultStatusHandler(int severity, int code, String message, Exception exception) {
+ processed(code);
+
+ if (message == null) {
+ if (exception != null)
+ message = exception.getMessage();
+ // extra check because the exception message can be null
+ if (message == null)
+ message = EMPTY_STRING;
+ }
+ return new Status(severity, PLUGIN_ID, code, message, exception);
+ }
+
+ /**
+ * checks what kind of change does <code>code</code> represent
+ * @param code
+ */
+ private void processed(int code) {
+ if ((code & IVersionCompare.ERROR_OCCURRED) != 0){
+ hasError = true;
+ return;
+ }
+ if ((code & IVersionCompare.MAJOR_CHANGE) != 0){
+ hasMajorChange = true;
+ return;
+ }
+ if ((code & IVersionCompare.MINOR_CHANGE) != 0){
+ hasMinorChange = true;
+ return;
+ }
+ if ((code & IVersionCompare.MICRO_CHANGE) != 0)
+ hasMicroChange = true;
+ }
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/ManifestHelper.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/ManifestHelper.java
new file mode 100755
index 000000000..7876a5713
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/ManifestHelper.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+import java.util.jar.Attributes.Name;
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.service.pluginconversion.PluginConversionException;
+import org.eclipse.osgi.service.pluginconversion.PluginConverter;
+import org.eclipse.osgi.util.ManifestElement;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.framework.BundleException;
+
+/**
+ * Helper class to manipulate manifest files.
+ */
+public class ManifestHelper implements VersionCompareConstants {
+
+ /**
+ * gets attributes from plugin.xml file in a plugin jar or directory denoted by <code>file</code>
+ * @param file File instance which denotes a plugin jar or directory
+ * @return Map which contains attributes of plugin.xml
+ */
+ private static Map getAttributesFromPluginManifest(File file) {
+ PluginConverter pluginConverter = Activator.getPluginConverter();
+ if (pluginConverter == null) {
+ // TODO log and return
+ // throw new CoreException(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, Messages.PluginVersionCompare_noPluginConverterInstanceMsg, null));
+ return null;
+ }
+ Dictionary pluginXML = null;
+ try {
+ pluginXML = pluginConverter.convertManifest(file, true, null, true, null);
+ } catch (PluginConversionException pce) {
+ // TODO log return
+ // throw new CoreException(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS.bind(Messages.PluginVersionCompare_couldNotConvertManifestMsg, file.getAbsoluteFile()), pce));
+ return null;
+ }
+ // we need to convert the dictionary into a map. Too bad.
+ Map result = new HashMap();
+ for (Enumeration e = pluginXML.keys(); e.hasMoreElements();) {
+ String key = (String) e.nextElement();
+ result.put(key, pluginXML.get(key));
+ }
+ return result;
+ }
+
+ /**
+ * get ManifestElement array of element denoted by <code>elementName</code>
+ * from manifest file of a jar or a plugin directory
+ *
+ * @param file File instance which represents a bundle directory(or jar file)
+ * @param keys the names of the elements we want to retrieve
+ * @return ManifestElement array of element denoted by <code>elementName</code> or <code>null</code> if
+ * element has not been found
+ * @throws CoreException <p>if {@link BundleException} has been thrown</p>
+ */
+ public static Map getElementsFromManifest(File file, String[] keys) throws CoreException {
+ Map result = new HashMap();
+ // try to get attributes from /META-INF/MANIFEST.MF file first
+ Attributes attributes = getAttributes(file);
+ // if we didn't get information, try to get information from plugin.xml file
+ Map map = attributes == null ? getAttributesFromPluginManifest(file) : convertAttributes(attributes);
+ // TODO log and return
+ if (map == null)
+ return result;
+ for (int i = 0; i < keys.length; i++) {
+ String value = (String) map.get(keys[i]);
+ if (value == null) {
+ // TODO log? we couldn't find the key we were looking for
+ result.put(keys[i], null);
+ continue;
+ }
+ try {
+ // get elements of attribute denoted by elementName
+ ManifestElement[] elements = ManifestElement.parseHeader(keys[i], value);
+ // we got a result so add it to the list and move to the next key
+ result.put(keys[i], elements);
+ } catch (BundleException be) {
+ throw new CoreException(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS.bind(Messages.PluginVersionCompare_couldNotParseHeaderMsg, value), be));
+ }
+ }
+ return result;
+ }
+
+ /*
+ * Convert the given Attributes object into a Map so we can use simple Map APIs on
+ * it later.
+ */
+ private static Map convertAttributes(Attributes attributes) {
+ Map result = new HashMap();
+ for (Iterator iter = attributes.keySet().iterator(); iter.hasNext();) {
+ Attributes.Name key = (Name) iter.next();
+ result.put(key.toString(), attributes.getValue(key));
+ }
+ return result;
+ }
+
+ /**
+ * Return the attributes that are in the given manifest file.
+ *
+ * @param file manifest file
+ * @return the attributes of the manifest file, or <code>null</code>
+ * @throws IOException <p>if any IOException has been thrown</p>
+ */
+ private static Attributes getAttributes(File file) {
+ // if file is a directory, we try to get /META-INF/MANIFEST.MF file under it
+ if (file.isDirectory()) {
+ File manifestFile = new File(file, BUNDLE_MANIFEST);
+ if (!manifestFile.exists())
+ return null;
+ InputStream input = null;
+ try {
+ input = new BufferedInputStream(new FileInputStream(manifestFile));
+ return new Manifest(input).getMainAttributes();
+ } catch (IOException e) {
+ return null;
+ } finally {
+ if (input != null)
+ try {
+ input.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ // if file is a jar, we try to get /META-INF/MANIFEST.MF file in it
+ if (file.getName().endsWith(JAR_FILE_EXTENSION)) {
+ try {
+ return new JarFile(file).getManifest().getMainAttributes();
+ } catch (IOException e) {
+ return null;
+ }
+ }
+ // we don't have a directory or JAR file
+ return null;
+ }
+
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/Messages.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/Messages.java
new file mode 100755
index 000000000..f3cc9c820
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/Messages.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import org.eclipse.osgi.util.NLS;
+
+public final class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.pde.tools.internal.versioning.messages";//$NON-NLS-1$
+
+ public static String FeatureModelTable_couldNotReadConfigFileMsg;
+ public static String FeatureModelTable_featureFileParseErrorMsg;
+
+ public static String FeatureModelTable_featureSourceErrorMsg;
+ public static String FeatureModelTable_urlConvertErrorMsg;
+ public static String FeatureVersionCompare_comparingFeatureMsg;
+ public static String FeatureVersionCompare_comparingReferenceMsg;
+ public static String FeatureVersionCompare_deletedFeaturePluginMsg;
+ public static String FeatureVersionCompare_destIncludedFeatureNotFoundMsg;
+ public static String FeatureVersionCompare_errorInVerifyPluginMsg;
+ public static String FeatureVersionCompare_errorReasonMsg;
+ public static String FeatureVersionCompare_featureFileErrorMsg;
+ public static String FeatureVersionCompare_incorrectNewVersionMsg;
+ public static String FeatureVersionCompare_incorrectNewVersionMsg2;
+
+ public static String FeatureVersionCompare_incorrectPluginVersionChange;
+ public static String FeatureVersionCompare_incorrectPluginVersionMsg;
+ public static String FeatureVersionCompare_inputErrorMsg;
+ public static String FeatureVersionCompare_lowerNewVersion;
+ public static String FeatureVersionCompare_nestedErrorOccurredMsg;
+ public static String FeatureVersionCompare_newAddedFeaturePlingMsg;
+ public static String FeatureVersionCompare_newIntroducedFeatureMsg;
+ public static String FeatureVersionCompare_newVersionLowerThanOldMsg;
+ public static String FeatureVersionCompare_noFeatureFoundMsg;
+ public static String FeatureVersionCompare_noFeaturesFoundInConfigMsg;
+ public static String FeatureVersionCompare_versionChangeIncorrectMsg;
+ public static String FeatureVersionCompare_pluginNotFoundMsg;
+ public static String FeatureVersionCompare_sourceIncludedFeatureNotFoundMsg;
+ public static String FeatureVersionCompare_verifyingFeatureMsg;
+ public static String JavaClassVersionCompare_classErrorOccurredMsg;
+ public static String JavaClassVersionCompare_classFileNotLoadedMsg;
+ public static String JavaClassVersionCompare_classMajorChangeMsg;
+ public static String JavaClassVersionCompare_classMicroChange;
+ public static String JavaClassVersionCompare_classMinorChangeMsg;
+ public static String JavaClassVersionCompare_classModifierChangedMsg;
+ public static String JavaClassVersionCompare_comparingClassMsg;
+ public static String JavaClassVersionCompare_deletedInterfaceMsg;
+ public static String JavaClassVersionCompare_deprecatedChangedMsg;
+ public static String JavaClassVersionCompare_descriptorChangedMsg;
+ public static String JavaClassVersionCompare_differentClassNameMsg;
+ public static String JavaClassVersionCompare_differentSuperClassMsg;
+ public static String JavaClassVersionCompare_inputStreamErrMsg;
+ public static String JavaClassVersionCompare_ModifierChangedMsg;
+ public static String JavaClassVersionCompare_newAddedExceptionMsg;
+ public static String JavaClassVersionCompare_newAddedInterfaceMsg;
+ public static String JavaClassVersionCompare_newAddedMsg;
+ public static String JavaClassVersionCompare_noLongerExistExceptionMsg;
+ public static String JavaClassVersionCompare_noLongerExistMsg;
+ public static String JavaClassVersionCompare_unexpectedTypeMsg;
+
+ public static String PluginVersionCompare_classPathJarNotFoundMsg;
+ public static String PluginVersionCompare_comparingPluginMsg;
+ public static String PluginVersionCompare_couldNotConvertManifestMsg;
+ public static String PluginVersionCompare_couldNotOpenJarMsg;
+ public static String PluginVersionCompare_couldNotParseHeaderMsg;
+ public static String PluginVersionCompare_couldNotReadAttributesMsg;
+ public static String PluginVersionCompare_couldNotReadClassMsg;
+ public static String PluginVersionCompare_couldNotReadClassPathMsg;
+ public static String PluginVersionCompare_couldNotReadManifestMsg;
+ public static String PluginVersionCompare_destinationClassNotFoundMsg;
+ public static String PluginVersionCompare_errorWhenCompareClassesMsg;
+ public static String PluginVersionCompare_failCloseJarEntryAfterExtractMsg;
+ public static String PluginVersionCompare_failCloseJarMsg;
+ public static String PluginVersionCompare_failCloseTmpAfterCreateMsg;
+ public static String PluginVersionCompare_failCreatTmpJarMsg;
+ public static String PluginVersionCompare_failExtractJarEntryMsg;
+ public static String PluginVersionCompare_failOpenJarEntryMsg;
+ public static String PluginVersionCompare_failOpenTmpJarMsg;
+ public static String PluginVersionCompare_finishedProcessPluginMsg;
+ public static String PluginVersionCompare_inputNotExistMsg;
+ public static String PluginVersionCompare_inValidClassPathMsg;
+ public static String PluginVersionCompare_noPluginConverterInstanceMsg;
+ public static String PluginVersionCompare_noValidClassFoundMsg;
+
+ public static String PluginVersionCompare_pluginErrorOccurredMsg;
+ public static String PluginVersionCompare_pluginMajorChangeMsg;
+ public static String PluginVersionCompare_pluginMicroChangeMsg;
+ public static String PluginVersionCompare_pluginMinorChangeMsg;
+ public static String PluginVersionCompare_sourceClassNotFoundMsg;
+
+ public static String VersionCompareDispatcher_closeFileFailedMsg;
+
+ public static String VersionCompareDispatcher_failedCreateDocMsg;
+
+ public static String VersionCompareDispatcher_failedWriteXMLFileMsg;
+ public static String VersionCompareDispatcher_fileNotFoundMsg;
+
+ public static String VersionCompareDispatcher_invalidXMLFileNameMsg;
+ public static String VersionCompareDispatcher_readPropertyFailedMsg;
+ public static String VersionVerifier_compareOKMsg;
+ public static String VersionVerifier_coreExceptionMsg;
+ public static String VersionVerifier_createFileErrorMsg;
+ public static String VersionVerifier_messageNumberMsg;
+ public static String VersionVerifier_mixedInputMsg;
+ public static String VersionVerifier_pathIsNotFileMsg;
+ public static String VersionVerifier_summaryMsg;
+ static {
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ // Do not instantiate
+ }
+} \ No newline at end of file
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/PluginVersionCompare.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/PluginVersionCompare.java
new file mode 100755
index 000000000..25d42cf78
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/PluginVersionCompare.java
@@ -0,0 +1,889 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+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.core.runtime.*;
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.util.IClassFileReader;
+import org.eclipse.osgi.util.ManifestElement;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.pde.tools.versioning.IVersionCompare;
+
+/**
+ * PluginVersionCompare
+ */
+public class PluginVersionCompare implements VersionCompareConstants {
+ private final static String CLASS_NAME = "PluginVersionCompare"; //$NON-NLS-1$
+ private final static int NEW_CLASS = 0;
+ private final static int DELETED_CLASS = 1;
+ private final static int CREATE_FILE_TIMES = 5;
+ // MultiStatus instance used to store error or warning messages
+ private MultiStatus finalResult;
+ // JavaClassVersionCompare instance
+ JavaClassVersionCompare classCompare;
+ //
+ private boolean hasMajorChange;
+ private boolean hasMinorChange;
+ private boolean hasMicroChange;
+ private boolean hasError;
+ // for debug
+ private long startTime;
+ private boolean DEBUG = false;
+ private static final String DEBUG_OPTION = VersionCompareConstants.PLUGIN_ID + "/debug/plugins"; //$NON-NLS-1$
+
+ /**
+ * constructor
+ */
+ public PluginVersionCompare() {
+ super();
+ classCompare = new JavaClassVersionCompare();
+ DEBUG = Activator.getBooleanDebugOption(DEBUG_OPTION);
+ }
+
+ /*
+ * Log the given debug message.
+ */
+ private void debug(String message) {
+ if (DEBUG) {
+ Activator.debug(message);
+ }
+ }
+
+ /**
+ * Compares the two given plug-ins which each other and reports a status object indicating
+ * whether or not the version number of the plug-ins have been incremented appropriately
+ * based on the relative changes.
+ *
+ * <p>
+ * The plug-in parameters can be instances of any of the following types:
+ * <ul>
+ * <li>{@link java.lang.String} - which denotes the plug-in's jar file name or directory
+ * <li>{@link java.net.URL} - which denotes the plug-in's jar file name or directory
+ * <li>{@link ManifestElement}[] - which denotes the manifest elements of Bundle_ClassPath of <code>plugin1</code>
+ * <li>{@link java.io.File} - which denotes the plug-in's jar file name or directory
+ * <li>{@link ManifestElement}[] - which denotes the manifest elements of Bundle_ClassPath of <code>plugin2</code>
+ * </ul>
+ * </p>
+ *
+ * @param plugin1 a plug-in reference
+ * @param elements1 Bundle_ClassPath of <code>plugin1</code>
+ * @param plugin2 a plug-in reference
+ * @param elements2 Bundle_ClassPath of <code>plugin2</code>
+ * @param status a MultiStatus instance to carry out compare information
+ * @param monitor IProgressMonitor instance which will monitor the progress during plugin comparing
+ * @return int number which indicates compare result, it could be MAJOR_CHANGE,MINOR_CHANGE,MICRO_CHANGE,or NO_CHANGE
+ * @throws CoreException if the parameters are of an incorrect type or if an error occurred during the comparison
+ */
+ protected int checkPluginVersions(MultiStatus status, Object plugin1, ManifestElement[] elements1, Object plugin2, ManifestElement[] elements2, IProgressMonitor monitor) throws CoreException {
+ try {
+ monitor = VersioningProgressMonitorWrapper.monitorFor(monitor);
+ monitor.beginTask(Messages.PluginVersionCompare_comparingPluginMsg, 100);
+ finalResult = status;
+ // convert input objects into Files
+ File file1 = convertInputObject(plugin1);
+ File file2 = convertInputObject(plugin2);
+ startTime = System.currentTimeMillis();
+ // initialize flags
+ hasError=false;
+ hasMajorChange = false;
+ hasMinorChange = false;
+ hasMicroChange = false;
+ // get class URL Tables
+ Map classFileURLTable1 = null;
+ Map classFileURLTable2 = null;
+ classFileURLTable1 = generateClassFileURLTableFromFile(file1, elements1);
+ // worked 1%
+ monitor.worked(1);
+ classFileURLTable2 = generateClassFileURLTableFromFile(file2, elements2);
+ // worked 1%
+ monitor.worked(1);
+ //
+ return checkPluginVersions(file1.getName(), classFileURLTable1, classFileURLTable2, new SubProgressMonitor(monitor, 98));
+ } finally {
+ monitor.done();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkPluginVersions(String, String, IProgressMonitor)
+ */
+ public int checkPluginVersions(MultiStatus status, Object plugin1, Object plugin2, IProgressMonitor monitor) throws CoreException {
+ try {
+ monitor = VersioningProgressMonitorWrapper.monitorFor(monitor);
+ monitor.beginTask(Messages.PluginVersionCompare_comparingPluginMsg, 100);
+ finalResult = status;
+ // convert input objects into Files
+ File file1 = convertInputObject(plugin1);
+ File file2 = convertInputObject(plugin2);
+ startTime = System.currentTimeMillis();
+ // initialize flags
+ hasError=false;
+ hasMajorChange = false;
+ hasMinorChange = false;
+ hasMicroChange = false;
+ // get class URL Tables
+ Map classFileURLTable1 = null;
+ Map classFileURLTable2 = null;
+ classFileURLTable1 = generateClassFileURLTable(file1);
+ // worked 2%
+ monitor.worked(2);
+ classFileURLTable2 = generateClassFileURLTable(file2);
+ // worked 2%
+ monitor.worked(2);
+ // check plugin version ( 96% workload)
+ return checkPluginVersions(file1.getName(), classFileURLTable1, classFileURLTable2, new SubProgressMonitor(monitor, 96));
+ } finally {
+ monitor.done();
+ }
+ }
+
+ /**
+ * Compares the corresponding classes denoted by URLS in <code>classFileURLTable1</code> to those in <code>classFileURLTable2</code>
+ * @param pluginName name of plugin
+ * @param classFileURLTable1 contains URL lists
+ * @param classFileURLTable2 contains URL lists
+ * @param monitor IProgressMonitor instance
+ * @return change with the highest priority
+ * @throws CoreException <p>if any nested CoreException has been thrown</p>
+ */
+ private int checkPluginVersions(String pluginName, Map classFileURLTable1, Map classFileURLTable2, IProgressMonitor monitor) {
+ // if both tables are empty, we treat it as no change
+ if (classFileURLTable1.size() == 0 && classFileURLTable2.size() == 0) {
+ debug(NLS.bind(Messages.PluginVersionCompare_finishedProcessPluginMsg, pluginName, String.valueOf(System.currentTimeMillis() - startTime)));
+ return IVersionCompare.NO_CHANGE;
+ }
+ // if size of table1 is 0, size of table2 is not 0, we treat it as major change (same as some class has been deleted)
+ if (classFileURLTable1.size() == 0) {
+ // check if there is any class no longer exists
+ processChangedClasseLists(classFileURLTable1, DELETED_CLASS);
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.PLUGIN_OVERALL_STATUS, NLS.bind(Messages.PluginVersionCompare_pluginMajorChangeMsg, pluginName), null));
+ debug(NLS.bind(Messages.PluginVersionCompare_finishedProcessPluginMsg, pluginName, String.valueOf(System.currentTimeMillis() - startTime)));
+ return IVersionCompare.MAJOR_CHANGE;
+ }
+ // if size of table2 is 0, size of table1 is not 0, we treat it as minor change (same as some class has been new added)
+ if (classFileURLTable2.size() == 0) {
+ // check if there is any class new added
+ processChangedClasseLists(classFileURLTable1, NEW_CLASS);
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.PLUGIN_OVERALL_STATUS, NLS.bind(Messages.PluginVersionCompare_pluginMinorChangeMsg, pluginName), null));
+ debug(NLS.bind(Messages.PluginVersionCompare_finishedProcessPluginMsg, pluginName, String.valueOf(System.currentTimeMillis() - startTime)));
+ return IVersionCompare.MINOR_CHANGE;
+ }
+ // compare classes
+ compareClasses(classFileURLTable1, classFileURLTable2, monitor);
+ // delete temporary directory
+ deleteTmpDirectory();
+ //
+ debug(NLS.bind(Messages.PluginVersionCompare_finishedProcessPluginMsg, pluginName, String.valueOf(System.currentTimeMillis() - startTime)));
+ // analysis result
+ if (hasError) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PLUGIN_OVERALL_STATUS, NLS.bind(Messages.PluginVersionCompare_pluginErrorOccurredMsg, pluginName), null));
+ return IVersionCompare.ERROR_OCCURRED;
+ }
+ if (hasMajorChange) {
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.PLUGIN_OVERALL_STATUS, NLS.bind(Messages.PluginVersionCompare_pluginMajorChangeMsg, pluginName), null));
+ return IVersionCompare.MAJOR_CHANGE;
+ }
+ if (hasMinorChange) {
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.PLUGIN_OVERALL_STATUS, NLS.bind(Messages.PluginVersionCompare_pluginMinorChangeMsg, pluginName), null));
+ return IVersionCompare.MINOR_CHANGE;
+ }
+ if (hasMicroChange) {
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.PLUGIN_OVERALL_STATUS, NLS.bind(Messages.PluginVersionCompare_pluginMicroChangeMsg, pluginName), null));
+ return IVersionCompare.MICRO_CHANGE;
+ }
+ return IVersionCompare.NO_CHANGE;
+ }
+
+ /**
+ * compares corresponding classes indicated by the URLs in two maps
+ * @param classFileURLTable1
+ * @param classFileURLTable2
+ * @param monitor IProgressMonitor instance
+ */
+ private void compareClasses(Map classFileURLTable1, Map classFileURLTable2, IProgressMonitor monitor) {
+ try {
+ monitor.beginTask("", classFileURLTable1.size() + 1); //$NON-NLS-1$
+ for (Iterator iterator1 = classFileURLTable1.keySet().iterator(); iterator1.hasNext();) {
+ if (monitor.isCanceled())
+ throw new OperationCanceledException();
+ Object key = iterator1.next();
+ // get URL lists of the same class file name
+ List value1 = (List) classFileURLTable1.get(key);
+ List value2 = (List) classFileURLTable2.get(key);
+ if (value2 == null) {
+ processChangedClasses(value1.toArray(), NEW_CLASS);
+ continue;
+ }
+ List classFileReaderList1 = generateClassFileReaderList(value1);
+ List classFileReaderList2 = generateClassFileReaderList(value2);
+ compareClasses(classFileReaderList1, classFileReaderList2, new SubProgressMonitor(monitor, 1));
+ // delete the value from classFileURLTable2
+ classFileURLTable2.remove(key);
+ }
+ // check if there is any class no longer exists
+ processChangedClasseLists(classFileURLTable2, DELETED_CLASS);
+ monitor.worked(1);
+ } finally {
+ monitor.done();
+ }
+ }
+
+ /**
+ * compares IClassFileReader instances in <code>list1</code> to the corresponding one
+ * in <code>list2</code>
+ * @param list1 contains IClassFileReader instances
+ * @param list2 contains IClassFileReader instances
+ * @param monitor IProgressMonitor instance
+ */
+ private void compareClasses(List list1, List list2, IProgressMonitor monitor) {
+ try {
+ monitor.beginTask("", list1.size() + 1); //$NON-NLS-1$
+ for (Iterator classIterator1 = list1.iterator(); classIterator1.hasNext();) {
+ if (monitor.isCanceled())
+ throw new OperationCanceledException();
+ IClassFileReader classFileReader1 = (IClassFileReader) classIterator1.next();
+ String className1 = charsToString(classFileReader1.getClassName());
+ Iterator classIterator2;
+ boolean beCompared = false;
+ for (classIterator2 = list2.iterator(); classIterator2.hasNext();) {
+ IClassFileReader classFileReader2 = (IClassFileReader) classIterator2.next();
+ if (className1.equals(charsToString(classFileReader2.getClassName()))) {
+ // compare two IClassFileReader instances and merge the result into finalResult
+ try {
+ processed(classCompare.checkJavaClassVersions(finalResult, classFileReader1, classFileReader2, new SubProgressMonitor(monitor, 1)));
+ } catch (CoreException ce) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_errorWhenCompareClassesMsg, charsToString(classFileReader1.getClassName())), null));
+ }
+ list2.remove(classFileReader2);
+ beCompared = true;
+ break;
+ }
+ }
+ if (!beCompared && shouldProcess(classFileReader1)) {
+ // new added class
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.PLUGIN_DETAIL_STATUS | IVersionCompare.MINOR_CHANGE, NLS.bind(Messages.PluginVersionCompare_destinationClassNotFoundMsg, charsToString(classFileReader1.getClassName())), null));
+ }
+ }
+ // no longer exist classes
+ for (Iterator iterator2 = list2.iterator(); iterator2.hasNext();) {
+ IClassFileReader classFileReader = (IClassFileReader) iterator2.next();
+ if (shouldProcess(classFileReader))
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.PLUGIN_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.PluginVersionCompare_sourceClassNotFoundMsg, charsToString(classFileReader.getClassName())), null));
+ }
+ monitor.worked(1);
+ } finally {
+ monitor.done();
+ }
+ }
+
+ /**
+ * processes no long existed classe lists contained in <code>map</code>
+ * @param map Map which contains class name and URL list pairs which no longer exist in the new plugin
+ */
+ private void processChangedClasseLists(Map map, int flag){
+ for (Iterator iterator = map.values().iterator(); iterator.hasNext();) {
+ List list = (List) iterator.next();
+ processChangedClasses(list.toArray(), flag);
+ }
+ }
+
+ /**
+ * process classes indicated by URL instances in <code>classArray</code> depending on <code>flag</code>
+ * if <code>flag</code> is NEW_CLASS, all the IClassFileReader instances in <code>classArray</code> are new added classes
+ * if <code>flag</code> is DELETED_CLASS, all the IClassFileReader instances in <code>classArray</code> are classes no longer exist
+ * @param classArray contains URL instances
+ * @param flag could be NEW_CLASS or DELETED_CLASS
+ */
+ private void processChangedClasses(Object[] classArray, int flag) {
+ if (classArray.length == 0)
+ return;
+ for (int i = 0; i < classArray.length; i++) {
+ if (!(classArray[i] instanceof URL))
+ continue;
+ try {
+ IClassFileReader classFileReader = ClassFileHelper.getReader(classArray[i]);
+ if (classFileReader == null) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_couldNotReadClassMsg, ((URL) classArray[i]).getFile()), null));
+ continue;
+ }
+ if (shouldProcess(classFileReader) && shouldProcess(charsToString(classFileReader.getClassName())))
+ if (flag == NEW_CLASS)
+ // new added class
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_OVERALL_STATUS | IVersionCompare.MINOR_CHANGE, NLS.bind(Messages.PluginVersionCompare_destinationClassNotFoundMsg, charsToString(classFileReader.getClassName())), null));
+ else if (flag == DELETED_CLASS)
+ // deleted class
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_OVERALL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.PluginVersionCompare_sourceClassNotFoundMsg, charsToString(classFileReader.getClassName())), null));
+ } catch (CoreException e) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_couldNotReadClassMsg, ((URL) classArray[i]).getFile()), e));
+ }
+ }
+ }
+
+ /**
+ * generates a List which stores IClassFileReader instances indicated by URLs in <code>list</code>
+ *
+ * @param list contains URL instances
+ * @return List contains IClassFileReader instances
+ */
+ private List generateClassFileReaderList(List list) {
+ ArrayList newList = new ArrayList(0);
+ if (list == null || list.size() == 0)
+ return newList;
+ for (Iterator iterator = list.iterator(); iterator.hasNext();) {
+ try {
+ IClassFileReader classFileReader = ClassFileHelper.getReader(iterator.next());
+ if (classFileReader == null)
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_couldNotReadClassMsg, ((URL) iterator.next()).getFile()), null));
+ else
+ newList.add(classFileReader);
+ } catch (CoreException e) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_couldNotReadClassMsg, ((URL) iterator.next()).getFile()), null));
+ }
+ }
+ return newList;
+ }
+
+ /**
+ * generates Map containing lists of URL instances indicates java classes
+ * which are under a plugin directory or included in a plugin jar file denoted by <code>file</code>.
+ * key is simple name of class file e.g. Foo.class
+ * value is a List which contains URLs pointing to classes which have the same simple file name
+ *
+ * @param file File instance which denotes a plugin directory or a plugin jar file
+ * @return Map containing URL instances
+ * @throws CoreException <p>if any nested CoreException has been caught</p>
+ */
+ private Map generateClassFileURLTable(File file) throws CoreException {
+ // get bundle class path
+ ManifestElement[] elements = null;
+ try {
+ elements = (ManifestElement[]) ManifestHelper.getElementsFromManifest(file, new String[] {BUNDLE_CLASSPATH}).get(BUNDLE_CLASSPATH);
+ } catch (CoreException ce) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_couldNotReadClassPathMsg, file.getAbsolutePath()), null));
+ }
+ return generateClassFileURLTableFromFile(file, elements);
+ }
+
+ /**
+ * converts input Object into File instance
+ * @param object input object
+ * @return File which represents <code>object</code>
+ * @throws CoreException <p>if type of <code>object</code> is unexpected</p>
+ * <p>or <code>object</code> does not represent an exist file or directory
+ */
+ private File convertInputObject(Object object) throws CoreException {
+ File file;
+ if (object instanceof String) {
+ // if object is a String
+ file = new File((String) object);
+ } else if (object instanceof URL)
+ // if object is an URL
+ file = new File(((URL) object).getFile());
+ else if (object instanceof File)
+ // if object is a File
+ file = (File) object;
+ else
+ // otherwise throw CoreException
+ throw new CoreException(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.ERROR, NLS.bind(Messages.JavaClassVersionCompare_unexpectedTypeMsg, object.getClass().getName()), null));
+ if (file.exists())
+ return file;
+ throw new CoreException(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.ERROR, NLS.bind(Messages.PluginVersionCompare_inputNotExistMsg, file.getAbsolutePath()), null));
+ }
+
+ /**
+ * generates Map containing lists of URL instances indicates java classes
+ * which are under a plugin directory or included in a plugin jar file denoted by <code>file</code>.
+ * key is simple name of class file e.g. Foo.class
+ * value is a List which contains URLs pointing to classes which have the same simple file name
+ *
+ * @param file File instance which denotes a plugin directory or a plugin jar file
+ * @param elements ManifestElement array of class path attribute
+ * @return Map containing URL instances
+ * @throws CoreException <p>if any nested CoreException has been caught</p>
+ */
+ private Map generateClassFileURLTableFromFile(File file, ManifestElement[] elements) throws CoreException {
+ Map table = new Hashtable(0);
+ if (file.isFile())
+ // if file is a file
+ getClassURLsFromJar(table, file, elements);
+ else if (file.isDirectory())
+ // if file is a directory
+ getClassURLsFromDir(table, file, elements);
+ if (table.size() == 0)
+ finalResult.merge(resultStatusHandler(IStatus.WARNING, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.PluginVersionCompare_noValidClassFoundMsg, file.getAbsolutePath()), null));
+ return table;
+ }
+
+ /**
+ * gets URL instances indicates java classes which are included in a plugin jar file denoted by <code>file</code>.
+ * and set them into <code>map</code>
+ * key is simple name of class file e.g. Foo.class
+ * value is a List which contains URLs pointing to classes which have the same simple file name
+ *
+ * @param map Map used to store URL instances
+ * @param file File instance which denotes a jar file
+ * @param elements ManifestElement array of class path attribute
+ * @throws CoreException <p>if jar file could not be loaded successfully</p>
+ * <p>or any nested CoreException has been caught</p>
+ *
+ */
+ private void getClassURLsFromJar(Map map, File file, ManifestElement[] elements) throws CoreException {
+ // check if file is a jar file
+ if (!isGivenTypeFile(file, JAR_FILE_EXTENSION))
+ return;
+ JarFile jarFile;
+ try {
+ jarFile = new JarFile(file);
+ } catch (IOException ioe) {
+ throw new CoreException(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.ERROR, NLS.bind(Messages.PluginVersionCompare_couldNotOpenJarMsg, file.getAbsolutePath()), ioe));
+ }
+ if (elements == null)
+ // if elements is null, we consider the class path as "."
+ getAllClassURLsInJar(map, jarFile);
+ else {
+ // check elements
+ for (int i = 0; i < elements.length; i++) {
+ if (elements[i].getValue().equals(DOT_MARK))
+ getAllClassURLsInJar(map, jarFile);
+ else {
+ // class path element is supposed to be "." or "*.jar"
+ if (!new Path(elements[i].getValue()).getFileExtension().equals(JAR_FILE_EXTENSION)) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PLUGIN_DETAIL_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_inValidClassPathMsg, elements[i].getValue(), file.getAbsolutePath()), null));
+ continue;
+ }
+ // if the jar entry indicates a nested jar file, we get IClassFileReaders of all the classes in it
+ JarEntry entry = jarFile.getJarEntry(elements[i].getValue());
+ if (entry != null) {
+ JarFile tempJarFile = null;
+ // get tmp file indicated by entry
+ File tmpFile = getTmpFile(jarFile, entry);
+ if (tmpFile == null)
+ // if failed to get tmp file, continue to check next element
+ continue;
+ try {
+ // generate a JarFile of the tmp file
+ tempJarFile = new JarFile(tmpFile);
+ } catch (IOException ioe) {
+ Object[] msg = {tmpFile.getAbsoluteFile(), entry.getName(), file.getAbsolutePath()};
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_failOpenTmpJarMsg, msg), ioe));
+ // continue to check next element
+ continue;
+ }
+ // get URLs of all classes in the jar
+ getAllClassURLsInJar(map, tempJarFile);
+ } else
+ finalResult.merge(resultStatusHandler(IStatus.WARNING, IVersionCompare.PLUGIN_DETAIL_STATUS, NLS.bind(Messages.PluginVersionCompare_classPathJarNotFoundMsg, elements[i].getValue(), file.getAbsolutePath()), null));
+ }
+ }
+ }
+ // close jar file
+ try {
+ jarFile.close();
+ } catch (IOException ioe) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_failCloseJarMsg, jarFile.getName()), ioe));
+ }
+ }
+
+ /**
+ * delete temporary directory used by this class
+ *
+ */
+ private void deleteTmpDirectory() {
+ // get java tmp directory
+ IPath tmpPath = getJavaTmpPath();
+ // find the directory for this plugin
+ tmpPath = tmpPath.append(PLUGIN_ID);
+ // find the directory for this class
+ tmpPath = tmpPath.append(CLASS_NAME);
+ // delete all the files and directories
+ File tmpDir = tmpPath.toFile();
+ deleteTmpFile(tmpDir);
+ }
+
+ /**
+ * delete all the files and directories under <code>dir</code>
+ * @param file
+ */
+ private void deleteTmpFile(File dir) {
+ if (!dir.exists())
+ return;
+ if (dir.isFile())
+ dir.delete();
+ File[] files = dir.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isFile()) {
+ files[i].delete();
+ } else
+ deleteTmpFile(files[i]);
+ }
+ dir.delete();
+ }
+
+ /**
+ * get URLs of all the classes which is in <code>jar</code>, and
+ * put them into <code>map</code>
+ * @param map map used to store URLs of all the classes
+ * @param jar jar file
+ */
+ private void getAllClassURLsInJar(Map map, JarFile jar) {
+ // get JarEntrys
+ Enumeration enumeration = jar.entries();
+ String jarURLString = jar.getName() + JAR_URL_SEPARATOR;
+ String classURLString;
+ for (; enumeration.hasMoreElements();) {
+ JarEntry jarEntry = (JarEntry) enumeration.nextElement();
+ // get URL for JarEntry which represents a java class file
+ if (!isValidClassJarEntry(jarEntry))
+ continue;
+ if (!shouldProcess(jarEntry.getName()))
+ continue;
+ classURLString = jarURLString + jarEntry.getName();
+ URL classFileURL = null;
+ try {
+ classFileURL = new URL(JAR_URL_HEAD + classURLString);
+ } catch (MalformedURLException e) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.FeatureModelTable_urlConvertErrorMsg, classURLString), e));
+ // do next
+ continue;
+ }
+ // try to get URL list
+ IPath entryPath = new Path(jarEntry.getName());
+ List urls = (List) map.get(entryPath.lastSegment());
+ if (urls == null) {
+ urls = new ArrayList(0);
+ urls.add(classFileURL);
+ } else
+ urls.add(classFileURL);
+ // put file name and list into map
+ map.put(entryPath.lastSegment(), urls);
+ }
+ }
+
+ /**
+ * get File instance which indicates the full path of the temporary jar file
+ * which is denoted by <code>jarEntry</code>.
+ * jar file denoted by <code>jarEntry</code> will be extracted to the java
+ * tmp directory and then be returned as a File instance
+ *
+ * @param jarFile
+ * @param jarEntry
+ * @return File indicates the full path of the temporary jar file or <code>null</code>
+ * if could not get the tmp file successfully
+ */
+ private File getTmpFile(JarFile jarFile, JarEntry jarEntry) {
+ // get java tmp directory
+ IPath tmpPath = getJavaTmpPath();
+ // create a directory for this plugin
+ tmpPath = tmpPath.append(PLUGIN_ID);
+ // create a directory for this plugin
+ tmpPath = tmpPath.append(CLASS_NAME);
+ // get path represented by jarEntry
+ IPath entryPath = new Path(jarEntry.getName());
+ // generate tmp directory
+ tmpPath = tmpPath.append(entryPath.removeLastSegments(1));
+ File tmpDir = tmpPath.toFile();
+ // if the tmp directory does not exist, make it
+ if (!tmpDir.exists())
+ tmpDir.mkdirs();
+ // get OutputStream of the tmp file
+ IPath tmpFile = null;
+ OutputStream out = null;
+ int i = 0;
+ while (out == null) {
+ // generate the full path of the tmp file(directory/file name)
+ tmpFile = tmpPath.append(generateTmpFileName(entryPath.lastSegment()));
+ try {
+ out = new BufferedOutputStream(new FileOutputStream(tmpFile.toFile()));
+ } catch (IOException ioe) {
+ i++;
+ //we try to create the tmp file for 5 times if any IOException has been caught
+ if (i == CREATE_FILE_TIMES) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_failCreatTmpJarMsg, tmpFile.toOSString()), ioe));
+ return null;
+ }
+ }
+ }
+ InputStream in = null;
+ try {
+ try {
+ // get InputStream of jarEntry
+ in = new BufferedInputStream(jarFile.getInputStream(jarEntry));
+ } catch (IOException ioe) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_failOpenJarEntryMsg, jarEntry.getName()), ioe));
+ return null;
+ }
+ // extract the file from jar to the tmp file
+ int readResult;
+ try {
+ while ((readResult = in.read()) != -1)
+ out.write(readResult);
+ } catch (IOException ioe) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_failExtractJarEntryMsg, jarEntry.getName()), ioe));
+ return null;
+ } finally {
+ try {
+ // ensure the input stream is closed
+ if (in != null) {
+ in.close();
+ in = null;
+ }
+ } catch (IOException ioe) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_failCloseJarEntryAfterExtractMsg, jarEntry.getName()), ioe));
+ }
+ }
+ } finally {
+ try {
+ // ensure the output stream is closed
+ if (out != null) {
+ out.close();
+ out = null;
+ }
+ } catch (IOException ioe) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.PluginVersionCompare_failCloseTmpAfterCreateMsg, tmpFile.toOSString()), ioe));
+ }
+ }
+ return tmpFile == null ? null : tmpFile.toFile();
+ }
+
+ /**
+ * generates file name with current time stamp in the front
+ * e.g.: file.jar --> 1152797697531.jar
+ * @param fileName
+ * @return generated file name
+ */
+ private String generateTmpFileName(String fileName) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(System.currentTimeMillis());
+ int index = fileName.lastIndexOf(DOT_MARK);
+ if (index == -1)
+ return buffer.toString();
+ buffer.append(fileName.substring(index));
+ return buffer.toString();
+ }
+
+ /**
+ * gets URL instances indicates java classes which are under in a plugin directory denoted by <code>dir</code>.
+ * and set them into <code>map</code>
+ * key is simple name of class file e.g. Foo.class
+ * value is a List which contains URLs pointing to classes which have the same simple file name
+ *
+ * @param map Map used to store URL instances
+ * @param dir File instance which denotes a directory on file-system
+ * @param elements ManifestElement array of class path attribute
+ * @throws CoreException <p>if nested CoreException has been caught</p>
+ */
+ private void getClassURLsFromDir(Map map, File dir, ManifestElement[] elements) throws CoreException {
+ if (elements == null)
+ // if elements is null, we consider the class path as "."
+ getAllClassURLsUnderDir(map, dir);
+ else {
+ for (int i = 0; i < elements.length; i++) {
+ if (elements[i].getValue().equals(DOT_MARK))
+ getAllClassURLsUnderDir(map, dir);
+ else {
+ IPath path = new Path(dir.getAbsolutePath());
+ path = path.append(elements[i].getValue());
+ // class path element is supposed to be "." or "*.jar"
+ if (!path.getFileExtension().equals(JAR_FILE_EXTENSION))
+ finalResult.merge(resultStatusHandler(IStatus.WARNING, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.PluginVersionCompare_inValidClassPathMsg, elements[i].getValue(), dir.getAbsolutePath()), null));
+ File jarFile = path.toFile();
+ if (jarFile.exists())
+ getClassURLsFromJar(map, jarFile, null);
+ else
+ finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.PLUGIN_DETAIL_STATUS, NLS.bind(Messages.PluginVersionCompare_classPathJarNotFoundMsg, elements[i].getValue(), dir.getAbsolutePath()), null));
+ }
+ }
+ }
+ }
+
+ /**
+ * checks if the class denoted by <code>className</code> need to be processed.
+ * @param className class name or class file name
+ * @return <code>true</code> if className does not include "/internal/", "\internal\", and ".internal."
+ * <code>false</code> otherwise
+ */
+ private boolean shouldProcess(String className) {
+ return className.indexOf("/internal/") == -1 && className.indexOf("\\internal\\") == -1 && className.indexOf("\\.internal\\.") == -1; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ /**
+ * checks if the class denoted by <code>classFileReader</code> need to be processed.
+ * @param classFileReader IClassFileReader instance
+ * @return <code>true</code> if access flag of the class is public or protected
+ * <code>false</code> otherwise
+ */
+ private boolean shouldProcess(IClassFileReader classFileReader) {
+ return Flags.isPublic(classFileReader.getAccessFlags()) || Flags.isProtected(classFileReader.getAccessFlags());
+ }
+
+ /**
+ * gets URLs of all "*.class" file under directory <code>dir</code> and its sub-directories
+ * and put them into <code>map</code>
+ * @param map Map used to store IClassFileReader instance
+ * @param dir directory
+ */
+ private void getAllClassURLsUnderDir(Map map, File dir) {
+ // if file is a directory, get URLs of "*.class" files under the directory and its sub-directories
+ File[] classFiles = dir.listFiles(new VersionClassDirFilter(CLASS_FILE_EXTENSION));
+ if (classFiles == null) {
+ return;
+ }
+ for (int i = 0; i < classFiles.length; i++) {
+ File file = classFiles[i];
+ if (classFiles[i].isDirectory())
+ // get URLs of class files under sub directory
+ getAllClassURLsUnderDir(map, classFiles[i]);
+ else if (isGivenTypeFile(file, CLASS_FILE_EXTENSION)) {
+ if (!shouldProcess(file.getAbsolutePath()))
+ continue;
+ // get URL of class file
+ URL classFileURL = null;
+ try {
+ classFileURL = classFiles[i].toURL();
+ } catch (MalformedURLException e) {
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.FeatureModelTable_urlConvertErrorMsg, classFiles[i].getAbsolutePath()), e));
+ // do next
+ continue;
+ }
+ if (classFileURL == null)
+ finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.FeatureModelTable_urlConvertErrorMsg, classFiles[i].getAbsolutePath()), null));
+ else {
+ // try to get URL list
+ List urls = (List) map.get(file.getName());
+ if (urls == null) {
+ urls = new ArrayList(0);
+ urls.add(classFileURL);
+ } else
+ urls.add(classFileURL);
+ // put file name and list into map
+ map.put(file.getName(), urls);
+ }
+ }
+ }
+ }
+
+ /**
+ * converts char array to String
+ * @param chars array of char
+ * @return String which represents the content of <code>chars</code>
+ */
+ private String charsToString(char[] chars) {
+ return new String(chars);
+ }
+
+ /**
+ * Checks whether or not the given file potentially represents a given type file on the file-system.
+ *
+ * @param file File instance which denotes to file on the file-system
+ * @param type file type(e.g. "java","class", "jar")
+ * @return <code>true</code> <code>file</code> exists and is a given type file,
+ * <code>false</code> otherwise
+ */
+ private boolean isGivenTypeFile(File file, String type) {
+ IPath path = new Path(file.getAbsolutePath());
+ return file.isFile() && path.getFileExtension().equals(type);
+ }
+
+ /**
+ * Checks whether or not the given JarEntry potentially represents a valid java class file,
+ * we filter out class file like "Foo$0.class".
+ *
+ * @param entry JarEntry instance
+ * @param type JarEntry type(e.g. "class")
+ * @return <code>true</code> <code>entry</code> exists and is a valid java class JarEntry,
+ * <code>false</code> otherwise
+ */
+ private boolean isValidClassJarEntry(JarEntry entry) {
+ IPath path = new Path(entry.toString());
+ // get file extension
+ String extension = path.getFileExtension();
+ if (extension == null)
+ return false;
+ if (!extension.equals(CLASS_FILE_EXTENSION))
+ return false;
+ int extensionIndex = path.lastSegment().lastIndexOf(extension);
+ if (extensionIndex == -1)
+ return false;
+ // get name of the file (without ".class")
+ String fileName = path.lastSegment().substring(0, extensionIndex - 1);
+ try {
+ int dollarIndex = fileName.lastIndexOf(DOLLAR_MARK);
+ // if no "$" in the file name, it is what we want
+ if (dollarIndex == -1)
+ return true;
+ // if the sub-String after "$" is all number, it is not what we want
+ Long.parseLong(fileName.substring(dollarIndex + 1));
+ return false;
+ } catch (NumberFormatException nfe) {
+ // if the sub-String after "$" is not all number, it is what we want
+ return true;
+ }
+ }
+
+ /**
+ * get java tmp directory IPath from system properties
+ * @return IPath instance which indicates java tmp directory
+ */
+ private IPath getJavaTmpPath() {
+ Properties properties = System.getProperties();
+ return new Path(properties.getProperty(JAVA_TMP_DIR_PROPERTY));
+ }
+
+ /**
+ * Return a new status object populated with the given information.
+ *
+ * @param severity severity of status
+ * @param code indicates type of this IStatus instance, it could be one of: FEATURE_OVERALL_STATUS,
+ * FEATURE_DETAIL_STATUS, PLUGIN_OVERALL_STATUS, PLUGIN_DETAIL_STATUS, PROCESS_ERROR_STATUS,
+ * CLASS_OVERALL_STATUS, CLASS_DETAIL_STATUS
+ * @param message the status message
+ * @param exception exception which has been caught, or <code>null</code>
+ * @return the new status object
+ */
+ private IStatus resultStatusHandler(int severity, int code, String message, Exception exception) {
+ processed(code);
+ if (message == null) {
+ if (exception != null)
+ message = exception.getMessage();
+ // extra check because the exception message can be null
+ if (message == null)
+ message = EMPTY_STRING;
+ }
+ return new Status(severity, PLUGIN_ID, code, message, exception);
+ }
+
+ /**
+ * checks what kind of change does <code>result</code> represent
+ * @param result compare result
+ */
+ private void processed(int result) {
+ if ((result & IVersionCompare.ERROR_OCCURRED) != 0){
+ hasError = true;
+ return;
+ }
+ if ((result & IVersionCompare.MAJOR_CHANGE) != 0){
+ hasMajorChange = true;
+ return;
+ }
+ if ((result & IVersionCompare.MINOR_CHANGE) != 0){
+ hasMinorChange = true;
+ return;
+ }
+ if ((result & IVersionCompare.MICRO_CHANGE) != 0)
+ hasMicroChange = true;
+ }
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionClassDirFilter.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionClassDirFilter.java
new file mode 100755
index 000000000..0f9663c07
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionClassDirFilter.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import java.io.File;
+import java.io.FileFilter;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+/**
+ * This class implements the FileFilter interface. Instance of this class may be
+ * passed to the listFiles(FileFilter) method of the File class
+ *
+ */
+public class VersionClassDirFilter implements FileFilter {
+ private String fileExtension;
+
+ /**
+ * Constructor
+ *
+ * @param fileExtension the file extension to filter on
+ */
+ public VersionClassDirFilter(String fileExtension) {
+ super();
+ this.fileExtension = fileExtension;
+ }
+
+ /**
+ * Returns <code>true</code> if the given file is a directory or its extension matches the file extension for this
+ * filter and <code>false</code> otherwise.
+ *
+ * @param file the abstract pathname to be tested
+ * @return <code>true</code> if the file is a directory , or its extension matches this filter's file extension
+ * <code>false</code> otherwise
+ */
+ public boolean accept(File file) {
+ if (file.isDirectory()) {
+ return true;
+ }
+
+ IPath path = new Path(file.getAbsolutePath());
+ String extension = path.getFileExtension();
+ if (extension == null) {
+ if (fileExtension == null || fileExtension.trim().equals("")) //$NON-NLS-1$
+ return true;
+ else
+ return false;
+ } else {
+ if (path.getFileExtension().equals(fileExtension))
+ return true;
+ else
+ return false;
+ }
+ }
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionCompareConstants.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionCompareConstants.java
new file mode 100755
index 000000000..de1f88c71
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionCompareConstants.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+public interface VersionCompareConstants {
+ public static final String PLUGIN_ID = "org.eclipse.pde.tools.versioning"; //$NON-NLS-1$
+ public final static String BUNDLE_MANIFEST = "META-INF/MANIFEST.MF"; //$NON-NLS-1$
+ public final static String BUNDLE_CLASSPATH = "Bundle-ClassPath"; //$NON-NLS-1$
+ public final static String BUNDLE_SYMBOLICNAME = "Bundle-SymbolicName"; //$NON-NLS-1$
+ public final static String BUNDLE_VERSION = "Bundle-Version"; //$NON-NLS-1$
+ public final static String BUNDLE_LOCATION = "Bundle-Location"; //$NON-NLS-1$
+ public final static String JAVA_TMP_DIR_PROPERTY = "java.io.tmpdir";//$NON-NLS-1$
+ public final static String PLUGIN_DIR_NAME = "plugins"; //$NON-NLS-1$
+ public static final String FEATURES_FILE_NAME = "feature.xml"; //$NON-NLS-1$
+ public static final String CONFIGURATION_FILE_NAME = "platform.xml"; //$NON-NLS-1$
+ public static final String JAVA_FILE_EXTENSION = "java"; //$NON-NLS-1$
+ public static final String CLASS_FILE_EXTENSION = "class"; //$NON-NLS-1$
+ public static final String JAR_FILE_EXTENSION = "jar"; //$NON-NLS-1$
+ public static final String PLATFORM_PROTOCOL = "platform"; //$NON-NLS-1$
+ public static final String FEATURE_TITLE = "feature"; //$NON-NLS-1$
+ public static final String PLUGIN_TITLE = "plugin"; //$NON-NLS-1$
+ public static final String FIELD_TITLE = "field"; //$NON-NLS-1$
+ public static final String METHOD_TITLE = "method"; //$NON-NLS-1$
+ public static final String JAR_URL_HEAD = "jar:file:"; //$NON-NLS-1$
+ public static final String JAR_URL_SEPARATOR = "!/"; //$NON-NLS-1$
+ public static final String WILD_CAST_STRING = ".*"; //$NON-NLS-1$
+ public static final String DOT_QUOTE_STRING = "\\."; //$NON-NLS-1$
+ public static final int DEFAULT_MODIFIER_TESTER = 0x0007;
+ public static final char START_CHAR = '*';
+ public static final char DOT_CHAR = '.';
+ public static final String ENCODING_TYPE = "UTF-8"; //$NON-NLS-1$
+ public static final String ROOT_ELEMENT_NAME = "CompareResult"; //$NON-NLS-1$
+ public static final String SEVERITY_ELEMENT_NAME = "Category"; //$NON-NLS-1$
+ public static final String CHILDREN_ELEMENT_NAME = "Info"; //$NON-NLS-1$
+ public static final String CODE_ATTRIBUTE_NAME = "Code"; //$NON-NLS-1$
+ public static final String MESSAGE_ATTRIBUTE_NAME = "Message"; //$NON-NLS-1$
+ public static final String XML_FILE_EXTENSION = "xml"; //$NON-NLS-1$
+ // marks
+ public static final String EMPTY_STRING = ""; //$NON-NLS-1$
+ public final static String DOLLAR_MARK = "$";//$NON-NLS-1$
+ public final static String DOT_MARK = ".";//$NON-NLS-1$
+ public static final String COMMA_MARK = ","; //$NON-NLS-1$
+ public static final String UNDERSCORE_MARK = "_"; //$NON-NLS-1$
+ public static final String KEY_SEPARATOR = "#"; //$NON-NLS-1$
+ public static final String SPACE = " "; //$NON-NLS-1$
+ public static final String START_MARK = "*"; //$NON-NLS-1$
+ // modifier String
+ public static final String ABSTRACT_STRING = "abstract"; //$NON-NLS-1$
+ public static final String PUBLIC_STRING = "public"; //$NON-NLS-1$
+ public static final String PRIVATE_STRING = "private"; //$NON-NLS-1$
+ public static final String FINAL_STRING = "final"; //$NON-NLS-1$
+ public static final String DEFAULT_STRING = "default"; //$NON-NLS-1$
+ public static final String STATIC_STRING = "static"; //$NON-NLS-1$
+ public static final String PROTECTED_STRING = "protected"; //$NON-NLS-1$
+ public static final String VOLATILE_STRING = "volatile"; //$NON-NLS-1$
+ public static final String NON_ABSTRACT_STRING = "non-abstract"; //$NON-NLS-1$
+ public static final String NON_STATIC_STRING = "non-static"; //$NON-NLS-1$
+ public static final String NON_FINAL_STRING = "non-final"; //$NON-NLS-1$
+ public static final String NON_VOLATILE_STRING = "non-volatile"; //$NON-NLS-1$
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionCompareDispatcher.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionCompareDispatcher.java
new file mode 100755
index 000000000..0e3fff344
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionCompareDispatcher.java
@@ -0,0 +1,322 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jdt.core.util.IClassFileReader;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.pde.tools.versioning.ICompareResult;
+import org.eclipse.pde.tools.versioning.IVersionCompare;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class VersionCompareDispatcher implements IVersionCompare {
+ private static final String NAME_STRING = "Name"; //$NON-NLS-1$
+ private static final String ERROR_STRING = "Error"; //$NON-NLS-1$
+ private static final String WARNING_STRING = "Warning"; //$NON-NLS-1$
+ private static final String INFO_STRING = "Information"; //$NON-NLS-1$
+ private static final String SEVERITY_CODE_STRING = "SeverityCode"; //$NON-NLS-1$
+ private static final String VERSION_STRING = "Version"; //$NON-NLS-1$
+ private static final String XML_VERSION = "1.0"; //$NON-NLS-1$
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkFeatureVersions(java.lang.String, java.lang.String, boolean, File, IProgressMonitor)
+ */
+ public IStatus checkFeatureVersions(String path1, String path2, boolean needPluginCompare, File versionOptionFile, IProgressMonitor monitor) throws CoreException {
+ return new FeatureVersionCompare().checkFeatureVersions(path1, path2, needPluginCompare, versionOptionFile, monitor);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkFeatureVersions(java.net.URL, java.net.URL, boolean, File, IProgressMonitor)
+ */
+ public IStatus checkFeatureVersions(URL configURL1, URL configURL2, boolean needPluginCompare, File compareOptionFile, IProgressMonitor monitor) throws CoreException {
+ return new FeatureVersionCompare().checkFeatureVersions(configURL1, configURL2, needPluginCompare, compareOptionFile, monitor);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkFeatureVersions(java.io.File, java.io.File, boolean, File, IProgressMonitor)
+ */
+ public IStatus checkFeatureVersions(File file1, File file2, boolean needPluginCompare, File compareOptionFile, IProgressMonitor monitor) throws CoreException {
+ return new FeatureVersionCompare().checkFeatureVersions(file1, file2, needPluginCompare, compareOptionFile, monitor);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkPluginVersions(String, String, IProgressMonitor)
+ */
+ public ICompareResult checkPluginVersions(String plugin1, String plugin2, IProgressMonitor monitor) throws CoreException {
+ MultiStatus finalResult = new MultiStatus(VersionCompareConstants.PLUGIN_ID, IStatus.OK, Messages.FeatureVersionCompare_errorReasonMsg, null);
+ return new CompareResult(new PluginVersionCompare().checkPluginVersions(finalResult, plugin1, plugin2, monitor), finalResult);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkPluginVersions(URL, URL, IProgressMonitor)
+ */
+ public ICompareResult checkPluginVersions(URL pluginURL1, URL pluginURL2, IProgressMonitor monitor) throws CoreException {
+ MultiStatus finalResult = new MultiStatus(VersionCompareConstants.PLUGIN_ID, IStatus.OK, Messages.FeatureVersionCompare_errorReasonMsg, null);
+ return new CompareResult(new PluginVersionCompare().checkPluginVersions(finalResult, pluginURL1, pluginURL2, monitor), finalResult);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkPluginVersions(File, File, IProgressMonitor)
+ */
+ public ICompareResult checkPluginVersions(File pluginFile1, File pluginFile2, IProgressMonitor monitor) throws CoreException {
+ MultiStatus finalResult = new MultiStatus(VersionCompareConstants.PLUGIN_ID, IStatus.OK, Messages.FeatureVersionCompare_errorReasonMsg, null);
+ return new CompareResult(new PluginVersionCompare().checkPluginVersions(finalResult, pluginFile1, pluginFile2, monitor), finalResult);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkJavaClassVersions(String, String, IProgressMonitor)
+ */
+ public ICompareResult checkJavaClassVersions(String javaClass1, String javaClass2, IProgressMonitor monitor) throws CoreException {
+ MultiStatus finalResult = new MultiStatus(VersionCompareConstants.PLUGIN_ID, IStatus.OK, Messages.FeatureVersionCompare_errorReasonMsg, null);
+ return new CompareResult(new JavaClassVersionCompare().checkJavaClassVersions(finalResult, javaClass1, javaClass2, monitor), finalResult);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkJavaClassVersions(URL, URL, IProgressMonitor)
+ */
+ public ICompareResult checkJavaClassVersions(URL javaClassURL1, URL javaClassURL2, IProgressMonitor monitor) throws CoreException {
+ MultiStatus finalResult = new MultiStatus(VersionCompareConstants.PLUGIN_ID, IStatus.OK, Messages.FeatureVersionCompare_errorReasonMsg, null);
+ return new CompareResult(new JavaClassVersionCompare().checkJavaClassVersions(finalResult, javaClassURL1, javaClassURL2, monitor), finalResult);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkJavaClassVersions(File, File, IProgressMonitor)
+ */
+ public ICompareResult checkJavaClassVersions(File javaClassFile1, File javaClassFile2, IProgressMonitor monitor) throws CoreException {
+ MultiStatus finalResult = new MultiStatus(VersionCompareConstants.PLUGIN_ID, IStatus.OK, Messages.FeatureVersionCompare_errorReasonMsg, null);
+ return new CompareResult(new JavaClassVersionCompare().checkJavaClassVersions(finalResult, javaClassFile1, javaClassFile1, monitor), finalResult);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkJavaClassVersions(InputStream, InputStream, IProgressMonitor)
+ */
+ public ICompareResult checkJavaClassVersions(InputStream javaClassInputStream1, InputStream javaClassInputStream2, IProgressMonitor monitor) throws CoreException {
+ MultiStatus finalResult = new MultiStatus(VersionCompareConstants.PLUGIN_ID, IStatus.OK, Messages.FeatureVersionCompare_errorReasonMsg, null);
+ return new CompareResult(new JavaClassVersionCompare().checkJavaClassVersions(finalResult, javaClassInputStream1, javaClassInputStream2, monitor), finalResult);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#checkJavaClassVersions(IClassFileReader, IClassFileReader, IProgressMonitor)
+ */
+ public ICompareResult checkJavaClassVersions(IClassFileReader classFileReader1, IClassFileReader classFileReader2, IProgressMonitor monitor) throws CoreException {
+ MultiStatus finalResult = new MultiStatus(VersionCompareConstants.PLUGIN_ID, IStatus.OK, Messages.FeatureVersionCompare_errorReasonMsg, null);
+ return new CompareResult(new JavaClassVersionCompare().checkJavaClassVersions(finalResult, classFileReader1, classFileReader2, monitor), finalResult);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#processCompareResult(IStatus status, int infoChoice)
+ */
+ public IStatus processCompareResult(IStatus status, int infoChoice) {
+ if (!status.isMultiStatus())
+ return status;
+ // create a new multi-status
+ MultiStatus multiStatus = new MultiStatus(VersionCompareConstants.PLUGIN_ID, IStatus.OK, status.getMessage(), null);
+ // get children status from result status
+ IStatus[] childStatus = status.getChildren();
+ for (int i = 0; i < childStatus.length; i++) {
+ if ((childStatus[i].getCode() & infoChoice) != 0) {
+ multiStatus.merge(childStatus[i]);
+ }
+ }
+ return multiStatus;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.pde.tools.versioning.IVersionCompare#processExclusionListFile(File file)
+ */
+ public Map processInclusionListFile(File file) throws CoreException {
+ Map table = new Hashtable();
+ FileInputStream fileInputStream = null;
+ try {
+ //create a properties instance
+ Properties ppt = new Properties();
+ // get InputStream of exclusion-list-file
+ fileInputStream = new FileInputStream(file);
+ // load property file
+ ppt.load(fileInputStream);
+ for (Iterator iterator = ppt.keySet().iterator(); iterator.hasNext();) {
+ Object key = iterator.next();
+ String property = ppt.getProperty((String) key);
+ if (property == null || property.trim().equals(VersionCompareConstants.EMPTY_STRING))
+ continue;
+ List propertyValueList = generateList(property.split(VersionCompareConstants.COMMA_MARK));
+ table.put(key, propertyValueList);
+ }
+ } catch (FileNotFoundException fnfe) {
+ throw new CoreException(new Status(IStatus.ERROR, VersionCompareConstants.PLUGIN_ID, IStatus.ERROR, NLS.bind(Messages.VersionCompareDispatcher_fileNotFoundMsg, file.getAbsolutePath()), fnfe));
+ } catch (IOException ioe) {
+ throw new CoreException(new Status(IStatus.ERROR, VersionCompareConstants.PLUGIN_ID, IStatus.ERROR, NLS.bind(Messages.VersionCompareDispatcher_readPropertyFailedMsg, file.getAbsolutePath()), ioe));
+ } finally {
+ if (fileInputStream != null) {
+ // close FileInputStream
+ try {
+ fileInputStream.close();
+ } catch (IOException ioe) {
+ throw new CoreException(new Status(IStatus.ERROR, VersionCompareConstants.PLUGIN_ID, IStatus.ERROR, NLS.bind(Messages.VersionCompareDispatcher_closeFileFailedMsg, file.getAbsolutePath()), ioe));
+ }
+ fileInputStream = null;
+ }
+ }
+ return table;
+ }
+
+ /**
+ * generates a List which stores instances in array <code>objects</code>
+ *
+ * @param objects instance objects
+ * @return List
+ */
+ private List generateList(Object[] objects) {
+ ArrayList list = new ArrayList(0);
+ if (objects == null || objects.length == 0)
+ return list;
+ for (int i = 0; i < objects.length; i++)
+ list.add(objects[i]);
+ return list;
+ }
+
+ /**
+ * writes out children statuses of <code>status</code> to XML file denoted by <code>fileName</code>
+ * @param status IStatus instance
+ * @param fileName String name of a XML file
+ * @throws CoreException <p>if any nested CoreException has been caught</p>
+ */
+ public void writeToXML(IStatus status, String fileName) throws CoreException {
+ Document doc = createXMLDoc(status);
+ writeToXML(doc, fileName);
+ }
+
+ /**
+ * creates a Document instance containing elements each of which represent a child status
+ * of <code>status</code>
+ * @param status IStatus instance
+ * @throws CoreException <p>if any ParserConfigurationException, or FactoryConfigurationError has been caught</p>
+ */
+ private Document createXMLDoc(IStatus status) throws CoreException {
+ DocumentBuilder docBuilder = null;
+ // create a DocumentBuilder instance
+ try {
+ docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ } catch (ParserConfigurationException pce) {
+ throw new CoreException(new Status(IStatus.ERROR, VersionCompareConstants.PLUGIN_ID, IStatus.ERROR, Messages.VersionCompareDispatcher_failedCreateDocMsg, pce));
+ } catch (FactoryConfigurationError fce) {
+ throw new CoreException(new Status(IStatus.ERROR, VersionCompareConstants.PLUGIN_ID, IStatus.ERROR, Messages.VersionCompareDispatcher_failedCreateDocMsg, fce));
+ }
+ // create a Document instance
+ Document doc = docBuilder.newDocument();
+ // create the root element
+ Element rootElement = doc.createElement(VersionCompareConstants.ROOT_ELEMENT_NAME);
+ rootElement.setAttribute(VERSION_STRING, XML_VERSION);
+ doc.appendChild(rootElement);
+ // create sub elements to contain different type of status
+ Element errorElement = doc.createElement(VersionCompareConstants.SEVERITY_ELEMENT_NAME);
+ errorElement.setAttribute(NAME_STRING, ERROR_STRING);
+ errorElement.setAttribute(SEVERITY_CODE_STRING, String.valueOf(IStatus.ERROR));
+ rootElement.appendChild(errorElement);
+ Element warningElement = doc.createElement(VersionCompareConstants.SEVERITY_ELEMENT_NAME);
+ warningElement.setAttribute(NAME_STRING, WARNING_STRING);
+ warningElement.setAttribute(SEVERITY_CODE_STRING, String.valueOf(IStatus.WARNING));
+ rootElement.appendChild(warningElement);
+ Element infoElement = doc.createElement(VersionCompareConstants.SEVERITY_ELEMENT_NAME);
+ infoElement.setAttribute(NAME_STRING, INFO_STRING);
+ infoElement.setAttribute(SEVERITY_CODE_STRING, String.valueOf(IStatus.INFO));
+ rootElement.appendChild(infoElement);
+ // get children statuses
+ IStatus[] children = status.getChildren();
+ if (children.length == 0)
+ return doc;
+ // create element for each children status
+ for (int i = 0; i < children.length; i++) {
+ switch (children[i].getSeverity()) {
+ case IStatus.ERROR : {
+ Element childElement = doc.createElement(VersionCompareConstants.CHILDREN_ELEMENT_NAME);
+ childElement.setAttribute(VersionCompareConstants.CODE_ATTRIBUTE_NAME, String.valueOf(children[i].getCode()));
+ childElement.setAttribute(VersionCompareConstants.MESSAGE_ATTRIBUTE_NAME, String.valueOf(children[i].getMessage()));
+ errorElement.appendChild(childElement);
+ break;
+ }
+ case IStatus.WARNING : {
+ Element childElement = doc.createElement(VersionCompareConstants.CHILDREN_ELEMENT_NAME);
+ childElement.setAttribute(VersionCompareConstants.CODE_ATTRIBUTE_NAME, String.valueOf(children[i].getCode()));
+ childElement.setAttribute(VersionCompareConstants.MESSAGE_ATTRIBUTE_NAME, String.valueOf(children[i].getMessage()));
+ warningElement.appendChild(childElement);
+ break;
+ }
+ case IStatus.INFO : {
+ Element childElement = doc.createElement(VersionCompareConstants.CHILDREN_ELEMENT_NAME);
+ childElement.setAttribute(VersionCompareConstants.CODE_ATTRIBUTE_NAME, String.valueOf(children[i].getCode()));
+ childElement.setAttribute(VersionCompareConstants.MESSAGE_ATTRIBUTE_NAME, String.valueOf(children[i].getMessage()));
+ infoElement.appendChild(childElement);
+ break;
+ }
+ }
+ }
+ return doc;
+ }
+
+ /**
+ * writes out <code>doc</code> to the xml file denoted by <code>fileName</code>
+ * @param doc Document instance
+ * @param fileName String which denotes a xml file
+ * @throws CoreException <p>if any TransformerConfigurationException, or TransformerException has been caught</p>
+ */
+ private void writeToXML(Document doc, String fileName) throws CoreException {
+ if (!isXMLfile(fileName))
+ throw new CoreException(new Status(IStatus.ERROR, VersionCompareConstants.PLUGIN_ID, IStatus.ERROR, NLS.bind(Messages.VersionCompareDispatcher_invalidXMLFileNameMsg, fileName), null));
+ // create a DOMSource instance
+ DOMSource doms = new DOMSource(doc);
+ // create a File instance
+ File file = new File(fileName);
+ // create a StreamResult instance of file
+ StreamResult streamResult = new StreamResult(file);
+ try {
+ // set output properties
+ TransformerFactory factory = TransformerFactory.newInstance();
+ Transformer transformer = factory.newTransformer();
+ Properties properties = transformer.getOutputProperties();
+ properties.setProperty(OutputKeys.ENCODING, VersionCompareConstants.ENCODING_TYPE);
+ transformer.setOutputProperties(properties);
+ // write out doc
+ transformer.transform(doms, streamResult);
+ } catch (TransformerConfigurationException tce) {
+ throw new CoreException(new Status(IStatus.ERROR, VersionCompareConstants.PLUGIN_ID, IStatus.ERROR, NLS.bind(Messages.VersionCompareDispatcher_failedWriteXMLFileMsg, fileName), tce));
+ } catch (TransformerException te) {
+ throw new CoreException(new Status(IStatus.ERROR, VersionCompareConstants.PLUGIN_ID, IStatus.ERROR, NLS.bind(Messages.VersionCompareDispatcher_failedWriteXMLFileMsg, fileName), te));
+ }
+ }
+
+ /**
+ * checks whether <code>file</code> represents a XML file
+ * @param fileName String name of a file
+ * @return <code>true</code> if <code>file</code> represents a XML file,
+ * <code>false</coc
+ */
+ private boolean isXMLfile(String fileName) {
+ IPath path = new Path(fileName);
+ if (path.isValidPath(fileName)) {
+ String extension = path.getFileExtension();
+ if (extension == null)
+ return false;
+ if (!extension.equals(VersionCompareConstants.XML_FILE_EXTENSION))
+ return false;
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionVerifier.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionVerifier.java
new file mode 100755
index 000000000..1e08b8d96
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersionVerifier.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import java.io.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.pde.tools.versioning.IVersionCompare;
+import org.eclipse.pde.tools.versioning.VersionCompareFactory;
+
+/**
+ * This is the headless version compare application.
+ */
+public class VersionVerifier implements IPlatformRunnable {
+ // path of new configuration file or feature directory
+ File newPath;
+ // path of old configuration file or feature directory
+ File oldPath;
+ // if need to compare plugins as objects
+ boolean needPluginCompare = false;
+ // path of the option file
+ String optionFilePath;
+ // path of the result file
+ String resultPath;
+ boolean isConfiguration = false;
+ boolean isDir = false;
+ boolean consoleOutput = false;
+
+ /*
+ * Prints the results using the given print writer. Closes the writer
+ * after processing.
+ */
+ private void printResult(IStatus status, PrintWriter writer) {
+ try {
+ // write out compare results to result file and also display them on screen
+ writer.println(Messages.VersionVerifier_summaryMsg);
+ if (status.isOK()) {
+ writer.println(Messages.VersionVerifier_compareOKMsg);
+ } else {
+ IStatus[] childStatus = status.getChildren();
+ writer.println();
+ if (childStatus.length == 0) {
+ writer.println(status.getMessage());
+ } else {
+ for (int i = 0; i < childStatus.length; i++) {
+ if (childStatus[i].isOK()) {
+ continue;
+ }
+ if (childStatus[i].getException() != null) {
+ String msg = childStatus[i].getMessage();
+ if (!msg.equals("")) { //$NON-NLS-1$
+ writer.println(msg);
+ }
+ writer.println(childStatus[i].getException().getMessage());
+ } else {
+ writer.println(childStatus[i].getMessage());
+ }
+ }
+ writer.println();
+ writer.println(NLS.bind(Messages.VersionVerifier_messageNumberMsg, String.valueOf(childStatus.length)));
+ }
+ }
+ } finally {
+ if (writer != null) {
+ writer.close();
+ writer = null;
+ }
+ }
+ }
+
+ /*
+ * Print out the given status object.
+ */
+ private void printResult(IStatus status, IVersionCompare versionCompare) {
+ // create a File instance for the result file
+ File resultFilePath = new File(resultPath);
+ File parentFilePath = null;
+ try {
+ if (!resultFilePath.exists()) {
+ // if the result file is not exist, we need to check its parent file
+ parentFilePath = resultFilePath.getParentFile();
+ if (parentFilePath.exists()) {
+ // if the parent file exists, we create the result file directly
+ resultFilePath.createNewFile();
+ } else {
+ // if the parent file does not exist, we create the parent file(directory) first
+ parentFilePath.mkdirs();
+ // and then create the result file
+ resultFilePath.createNewFile();
+ }
+ } else {
+ if (!resultFilePath.isFile()) {
+ System.out.println(NLS.bind(Messages.VersionVerifier_createFileErrorMsg, Messages.VersionVerifier_pathIsNotFileMsg));
+ return;
+ }
+ }
+ } catch (IOException ioe) {
+ System.out.println(NLS.bind(Messages.VersionVerifier_createFileErrorMsg, resultFilePath));
+ return;
+ }
+ // write the results to a XML file
+ try {
+ versionCompare.writeToXML(status, resultFilePath.getAbsolutePath());
+ } catch (CoreException ce) {
+ ce.printStackTrace();
+ }
+ // check to see if the user requested console output as well
+ if (consoleOutput)
+ printResult(status, new PrintWriter(System.out));
+ }
+
+ /*
+ * Print out a message describing how to run the application.
+ */
+ private void printUsage() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("Usage: java -cp startup.jar org.eclipse.core.launcher.Main -application org.eclipse.pde.tools.versioning.application -clean -new [path] -old [path] -option [path] -output [path] [-pluginCompare] [-consoleOutput]"); //$NON-NLS-1$
+ buffer.append("\n-new: path of new configuration file or features directory"); //$NON-NLS-1$
+ buffer.append("\n-old: path of old configuration file or features directory"); //$NON-NLS-1$
+ buffer.append("\n-option: path of compare option file (optional)"); //$NON-NLS-1$
+ buffer.append("\n-output: path of result XML file"); //$NON-NLS-1$
+ buffer.append("\n-pluginCompare: if need to compare plugins as objects (optional)"); //$NON-NLS-1$
+ buffer.append("\n-consoleOutput: print results to the system console (optional)"); //$NON-NLS-1$
+ System.out.println(buffer.toString());
+ }
+
+ /*
+ * Look at the given file path and determine if it is a configuration file
+ * or a features directory. Return the associated File object.
+ */
+ private File processPath(String pathString) {
+ IPath path = new Path(pathString);
+ File file = path.toFile();
+ // check to see if we are pointing to a configuration file
+ if ("platform.xml".equalsIgnoreCase(path.lastSegment())) //$NON-NLS-1$
+ isConfiguration = true;
+ // check if its a directory
+ isDir = file.isDirectory();
+ return file;
+ }
+
+ /*
+ * Process the command-line arguments and set up the local variables
+ * for the application.
+ */
+ private boolean processCommandLine(String[] parameters) {
+ // get parameters
+ for (int i = 0; i < parameters.length; i++) {
+ if (parameters[i].equalsIgnoreCase("-new")) { //$NON-NLS-1$
+ if ((i + 1 < parameters.length) && !parameters[i + 1].startsWith("-")) { //$NON-NLS-1$
+ i++;
+ newPath = processPath(parameters[i]);
+ if (isConfiguration && isDir) {
+ System.out.println(Messages.VersionVerifier_mixedInputMsg);
+ return false;
+ }
+ }
+ } else if (parameters[i].equalsIgnoreCase("-old")) { //$NON-NLS-1$
+ if ((i + 1 < parameters.length) && !parameters[i + 1].startsWith("-")) { //$NON-NLS-1$
+ i++;
+ oldPath = processPath(parameters[i]);
+ if (isConfiguration && isDir) {
+ System.out.println(Messages.VersionVerifier_mixedInputMsg);
+ return false;
+ }
+ }
+ } else if (parameters[i].equalsIgnoreCase("-option")) { //$NON-NLS-1$
+ if ((i + 1 < parameters.length) && !parameters[i + 1].startsWith("-")) { //$NON-NLS-1$
+ i++;
+ optionFilePath = parameters[i];
+ }
+ } else if (parameters[i].equalsIgnoreCase("-output")) { //$NON-NLS-1$
+ if ((i + 1 < parameters.length) && !parameters[i + 1].startsWith("-")) { //$NON-NLS-1$
+ i++;
+ resultPath = parameters[i];
+ }
+ } else if (parameters[i].equalsIgnoreCase("-pluginCompare")) { //$NON-NLS-1$
+ needPluginCompare = true;
+ } else if (parameters[i].equalsIgnoreCase("-consoleOutput")) { //$NON-NLS-1$
+ consoleOutput = true;
+ }
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IPlatformRunnable#run(java.lang.Object)
+ */
+ public Object run(Object args) {
+ // cast the args object into String array
+ boolean ok = processCommandLine((String[]) args);
+ // if any necessary parameter is missed, we display help message to tell
+ // user how to run this application in command line
+ if (!ok || newPath == null || oldPath == null || resultPath == null) {
+ printUsage();
+ return null;
+ }
+ // do the work, compare features included in new configuration(or feature directory)
+ // with those included in old configuration(or feature directory)
+ IVersionCompare ivc = new VersionCompareFactory().getVersionCompare();
+ IStatus status = null;
+ try {
+ status = ivc.checkFeatureVersions(newPath, oldPath, needPluginCompare, optionFilePath == null || optionFilePath.trim().equals("") ? null : new File(optionFilePath), null); //$NON-NLS-1$
+ } catch (CoreException ce) {
+ System.out.print(Messages.VersionVerifier_coreExceptionMsg);
+ System.out.println(ce.getMessage());
+ return null;
+ } catch (Exception e){
+ e.printStackTrace();
+ }
+ // print out the results
+ printResult(status, ivc);
+ return null;
+ }
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningDirFilter.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningDirFilter.java
new file mode 100755
index 000000000..32428a457
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningDirFilter.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import java.io.File;
+import java.io.FileFilter;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+/**
+ * This class implements the FileFilter interface. Instance of this class may be
+ * passed to the listFiles(FileFilter) method of the File class
+ *
+ */
+public class VersioningDirFilter implements FileFilter {
+ private String dirName;
+
+ /**
+ * Constructor for the class.
+ */
+ public VersioningDirFilter(String dirName) {
+ super();
+ this.dirName = dirName;
+ }
+
+ /**
+ * Constructor for the class.
+ */
+ public VersioningDirFilter() {
+ super();
+ this.dirName = null;
+ }
+
+ /**
+ * Returns <code>true</code> if the given file is a directory and <code>false</code> otherwise.
+ *
+ * @param file the abstract pathname to be tested
+ * @return <code>true</code> if the file is a directory and <code>false</code> otherwise
+ */
+ public boolean accept(File file) {
+ if (file.isDirectory()) {
+ if (dirName != null) {
+ IPath path = new Path(file.getAbsolutePath());
+ if (path.lastSegment().equals(dirName))
+ return true;
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+} \ No newline at end of file
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningFeatureFileFilter.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningFeatureFileFilter.java
new file mode 100755
index 000000000..217abc911
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningFeatureFileFilter.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import java.io.File;
+import java.io.FileFilter;
+
+/**
+ * This class implements the FileFilter interface. Instance of this class may be
+ * passed to the listFiles(FileFilter) method of the File class
+ *
+ */
+public class VersioningFeatureFileFilter implements FileFilter {
+ private String fileName;
+
+ /**
+ * Constructor for the class.
+ *
+ * @param fileName the filename to filter on
+ */
+ public VersioningFeatureFileFilter(String fileName) {
+ super();
+ this.fileName = fileName;
+ }
+
+ /**
+ * Returns <code>true</code> if the given file matches the name for this
+ * filter and <code>false</code> otherwise.
+ *
+ * @param file the abstract pathname to be tested
+ * @return <code>true</code> if the file matches this filter's name and<code>false</code> otherwise
+ */
+ public boolean accept(File file) {
+ if (file.isDirectory()) {
+ return false;
+ }
+
+ String name = file.getName();
+ if (name.equals(fileName)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningFilenameFilter.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningFilenameFilter.java
new file mode 100755
index 000000000..75789826f
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningFilenameFilter.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.regex.Pattern;
+
+/**
+ * This class implements the FilenameFilter interface. Instance of this class
+ * may be passed to the listFiles(FilenameFilter) method of the File class
+ *
+ */
+public class VersioningFilenameFilter implements FilenameFilter {
+ private Pattern pattern;
+
+ /**
+ * Constructor for this class. Initialize it with the given regular expression.
+ *
+ * @param featureRegex the regular expression to use for this filter
+ */
+ public VersioningFilenameFilter(String featureRegex) {
+ pattern = Pattern.compile(featureRegex);
+ }
+
+ /**
+ * Returns <code>true</code> if the given filename matches the regular
+ * expression for this filter, and <code>false</code> otherwise.
+ *
+ * @param dir the directory in which the file was found
+ * @param name the name of the file to be tested
+ * @return <code>true</code> if the name should be included in the file list and<code>false</code> otherwise
+ */
+ public boolean accept(File dir, String name) {
+ // Creates a matcher and matches the given input against the pattern.
+ return pattern.matcher(new File(name).getName()).matches();
+ }
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningProgressMonitorWrapper.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningProgressMonitorWrapper.java
new file mode 100755
index 000000000..6a6c41766
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/VersioningProgressMonitorWrapper.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.internal.versioning;
+
+import org.eclipse.core.runtime.*;
+
+/**
+ * a wrapper class of IProgressMonitor which provides methods to
+ * get access to the wrapped IProgressMonitor instance
+ */
+public class VersioningProgressMonitorWrapper extends ProgressMonitorWrapper {
+ // the wrapped monitor is not supposed to be used more than once,
+ // this flag will be set as true when the first time it is started, and
+ // will not be set as false when the monitor's task is done.
+ private boolean monitorStarted;
+
+ /**
+ * constructor
+ * @param monitor
+ */
+ public VersioningProgressMonitorWrapper(IProgressMonitor monitor) {
+ super(monitor);
+ monitorStarted = false;
+ }
+
+ /**
+ * get a new sub monitor of wrapped progress monitor
+ *
+ * @return IProgressMonitor instance
+ */
+ public IProgressMonitor getSubMonitor(int ticks) {
+ return new SubProgressMonitor(this.getWrappedProgressMonitor(), ticks);
+ }
+
+ /**
+ * starts the wrapped monitor
+ * @see IProgressMonitor#beginTask(String, int)
+ */
+ public void beginTask(String name, int totalWork) {
+ if (!monitorStarted) {
+ this.getWrappedProgressMonitor().beginTask(name, totalWork);
+ monitorStarted = true;
+ }
+ }
+
+ /**
+ * if <code>monitor</code> is <code>null</code> return a new NullProgressMonitor instance,
+ * otherwise return <code>monitor</code>
+ * @param monitor IProgressMonitor instance
+ * @return IProgressMonitor instance
+ */
+ public static IProgressMonitor monitorFor(IProgressMonitor monitor) {
+ return monitor == null ? new NullProgressMonitor() : monitor;
+ }
+} \ No newline at end of file
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/messages.properties b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/messages.properties
new file mode 100755
index 000000000..92ebcecdb
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/messages.properties
@@ -0,0 +1,102 @@
+###############################################################################
+# Copyright (c) 2006 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
+###############################################################################
+FeatureVersionCompare_errorInVerifyPluginMsg=Error occurred while verifying plugin "{0}" in feature (id "{1}"; version: "{2}"; location: "{3}").
+FeatureVersionCompare_errorReasonMsg=Errors occurred during feature verification.
+FeatureModelTable_urlConvertErrorMsg=Could not convert "{0}" into a valid URL.
+FeatureVersionCompare_featureFileErrorMsg=Feature manifest (feature.xml) file could not be successfully loaded from location "{0}".
+FeatureVersionCompare_verifyingFeatureMsg=Comparing Features......
+FeatureVersionCompare_comparingFeatureMsg=Comparing Feature {0}
+FeatureVersionCompare_comparingReferenceMsg=Comparing references......
+FeatureModelTable_featureFileParseErrorMsg=Could not parse feature file "{0}", it may not exist.
+FeatureModelTable_featureSourceErrorMsg="{0}" is neither a configuration file nor a feature directory.
+FeatureVersionCompare_incorrectNewVersionMsg=The version of the feature (id: "{0}"; version: "{1}"; location: "{2}") should be at least "{3}".
+FeatureVersionCompare_incorrectNewVersionMsg2=The version of the feature (id: "{0}"; version: "{1}"; location: "{2}") should be higher than "{3}".
+FeatureVersionCompare_incorrectPluginVersionMsg=The version of the plugin (id: "{0}"; version: "{1}"; location: "{2}") should be at least "{3}".
+FeatureVersionCompare_incorrectPluginVersionChange=Plugin (id: "{0}"; version: "{1}") got "{2}" change, but its "{3}" version has been increased.
+FeatureVersionCompare_inputErrorMsg=Inputs "{0}" or "{1}" could not be resolved correctly. They should be either both paths of configurations or both paths of feature directories.
+FeatureVersionCompare_sourceIncludedFeatureNotFoundMsg=Compare source feature "{0}" is included in feature (id: "{1}"; version: "{2}", location: "{3}"), but its feature model has not been found.
+FeatureVersionCompare_destIncludedFeatureNotFoundMsg=Compare destination feature "{0}" is included in feature (id: "{1}"; version: "{2}", location: "{3}"), but its feature model has not been found.
+FeatureVersionCompare_lowerNewVersion=The version "{0}" of {1} "{2}" in feature (id: "{3}";version: "{4}"; location: "{5}") is lower than its version "{6}" in feature (id: "{3}";version: "{7}"; location: "{8}").
+FeatureVersionCompare_nestedErrorOccurredMsg=Feature (id: "{0}";version: "{1}"; location: "{2}") could not be verified since errors occurred while verifying its included features or plugins.
+FeatureModelTable_couldNotReadConfigFileMsg=Could not read configuration file "{0}".
+FeatureVersionCompare_newVersionLowerThanOldMsg=The Version of feature (id: "{0}"; version: "{1}", location: "{2}") is lower than the version of feature(id: "{0}"; version: "{3}", location: "{4}").
+FeatureVersionCompare_noFeaturesFoundInConfigMsg=No feature has been found in configuration: "{0}".
+FeatureVersionCompare_noFeatureFoundMsg=No feature has been found under directory: "{0}".
+FeatureVersionCompare_versionChangeIncorrectMsg=Feature (id: "{0}"; version: "{1}", location: "{2}") got "{3}" change, but its "{4}" version has been increased.
+FeatureVersionCompare_pluginNotFoundMsg=Plugin "{0}" is included in feature (id: "{1}"; version: "{2}"; location: "{3}"), but it has not been found under "{4}".
+FeatureVersionCompare_newAddedFeaturePlingMsg= {0} "{1}" is new added into feature (id: "{2}"; version: "{3}", location: "{4}").
+FeatureVersionCompare_newIntroducedFeatureMsg=Feature (id: "{0}"; version: "{1}"; location: "{2}") is a new introduced feature.
+FeatureVersionCompare_deletedFeaturePluginMsg= {0} "{1}" no longer exists in feature (id: "{2}"; version: "{3}", location: "{4}").
+
+VersionVerifier_compareOKMsg=All of the versions are correct.
+VersionVerifier_coreExceptionMsg=CoreException occurred:
+VersionVerifier_createFileErrorMsg=Exception occurred while creating the output file "{0}".
+VersionVerifier_mixedInputMsg=Inputs should be either two paths of configurations or two paths of feature directories, but not mix of them.
+VersionVerifier_pathIsNotFileMsg=The specified output file path is not a file.
+VersionVerifier_messageNumberMsg=Number of message: {0}
+VersionVerifier_summaryMsg=Comparison result Summary:
+
+VersionCompareDispatcher_fileNotFoundMsg=Could not find exclusion list file "{0}".
+VersionCompareDispatcher_readPropertyFailedMsg=Could not read property from file "{0}".
+VersionCompareDispatcher_invalidXMLFileNameMsg="{0}" is not a valid XML file.
+VersionCompareDispatcher_failedWriteXMLFileMsg=Failed to write out the compare result to "{0}".
+VersionCompareDispatcher_closeFileFailedMsg=Failed to close file "{0}".
+VersionCompareDispatcher_failedCreateDocMsg=Failed to create XML file for the compare result.
+
+JavaClassVersionCompare_classFileNotLoadedMsg=Could not read class file from: "{0}".
+JavaClassVersionCompare_classErrorOccurredMsg=Error occurred while comparing class "{0}".
+JavaClassVersionCompare_classMajorChangeMsg=Class "{0}" has a major change.
+JavaClassVersionCompare_classMinorChangeMsg=Class "{0}" has a minor change.
+JavaClassVersionCompare_classModifierChangedMsg=Modifier of "{0}" has been changed from "{1}" to "{2}".
+JavaClassVersionCompare_differentClassNameMsg=Selected two classes(or java sources) do not have the same class name. One is "{0}", another is "{1}".
+JavaClassVersionCompare_differentSuperClassMsg=Super class of "{0}" has been changed from "{1}" to "{2}".
+JavaClassVersionCompare_deletedInterfaceMsg=Interface "{0}" has no longer been implemented in class "{1}".
+JavaClassVersionCompare_deprecatedChangedMsg={0} "{1}" has been deprecated in class "{2}".
+JavaClassVersionCompare_descriptorChangedMsg=Type of field "{0}" has been changed from "{1}" to "{2}" in class "{3}".
+JavaClassVersionCompare_inputStreamErrMsg=Could not read class file from provided InputSteam.
+JavaClassVersionCompare_ModifierChangedMsg=Modifier of {0} "{1}" has been changed from "{2}" to "{3}".
+JavaClassVersionCompare_newAddedInterfaceMsg=Interface "{0}" has been new implemented in class "{1}".
+JavaClassVersionCompare_newAddedMsg={0} "{1}" is new added into class "{2}".
+JavaClassVersionCompare_noLongerExistMsg={0} "{1}" no longer exists in class "{2}".
+JavaClassVersionCompare_classMicroChange=Class "{0}" has a micro change.
+JavaClassVersionCompare_newAddedExceptionMsg=Exceptions "{0}" have been new added to method "{1}" in class "{2}".
+JavaClassVersionCompare_noLongerExistExceptionMsg= Exceptions "{0}" are no longer thrown from method "{1}" in class "{2}".
+JavaClassVersionCompare_unexpectedTypeMsg= "{0}" is not an expected input type.
+JavaClassVersionCompare_comparingClassMsg=Comparing class......
+
+PluginVersionCompare_classPathJarNotFoundMsg=Corresponding jar file has not been found for class path element "{0}" in plugin "{1}".
+PluginVersionCompare_couldNotReadManifestMsg=Could not read manifest file of plugin "{0}" correctly.
+PluginVersionCompare_couldNotOpenJarMsg=Could not open jar file "{0}".
+PluginVersionCompare_comparingPluginMsg=Comparing Plugin
+PluginVersionCompare_couldNotReadAttributesMsg=Could not read attributes from manifest file of bundle "{0}".
+PluginVersionCompare_couldNotReadClassPathMsg=Could not read Bundle-ClassPath attributes from manifest file of plugin "{0}".
+PluginVersionCompare_couldNotReadClassMsg=Could not read class file "{0}".
+PluginVersionCompare_couldNotParseHeaderMsg=Could not parse manifest header "{0}".
+PluginVersionCompare_couldNotConvertManifestMsg=Could not convert "{0}" into manifest file.
+PluginVersionCompare_destinationClassNotFoundMsg=Class "{0}" is a new added class.
+PluginVersionCompare_noPluginConverterInstanceMsg=Could not get PluginConverter instance from OSGi framework.
+PluginVersionCompare_failCloseJarMsg=Failed to close jar file "{0}".
+PluginVersionCompare_failCloseJarEntryAfterExtractMsg=Failed to close jar entry "{0}".
+PluginVersionCompare_failExtractJarEntryMsg=Failed to extract jar entry "{0}" to temporary file.
+PluginVersionCompare_finishedProcessPluginMsg=Finished process plugin "{0}", used {1} milliseconds.
+PluginVersionCompare_failOpenJarEntryMsg=Failed to open jar entry "{0}".
+PluginVersionCompare_failOpenTmpJarMsg=Failed to open temporary jar file "{0}" of jar entry "{1}" of "{2}".
+PluginVersionCompare_failCloseTmpAfterCreateMsg=Failed to close temporary file "{0}" after creating.
+PluginVersionCompare_errorWhenCompareClassesMsg=Error occurred while comparing {0}.
+PluginVersionCompare_failCreatTmpJarMsg=Failed to create temporary file "{0}".
+PluginVersionCompare_inValidClassPathMsg="{0}" is not a valid class path element in manifest file of "{1}".
+PluginVersionCompare_inputNotExistMsg="{0}" does not represent an exist file or directory.
+PluginVersionCompare_noValidClassFoundMsg=No class in "{0}" is need to be compared.
+PluginVersionCompare_pluginMajorChangeMsg=Plugin "{0}" has a major change.
+PluginVersionCompare_pluginMinorChangeMsg=Plugin "{0}" has a minor change.
+PluginVersionCompare_pluginMicroChangeMsg=Plugin "{0}" has a micro change.
+PluginVersionCompare_pluginErrorOccurredMsg=Error occurred while comparing plugin "{0}".
+PluginVersionCompare_sourceClassNotFoundMsg=Class "{0}" is no longer existed.
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Entries b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Entries
new file mode 100644
index 000000000..0e2e75717
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Entries
@@ -0,0 +1,4 @@
+/ICompareResult.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+/IVersionCompare.java/1.1/Wed Dec 28 16:06:22 2011//Tr20080922
+/VersionCompareFactory.java/1.1/Thu Oct 5 17:45:07 2006//Tr20080922
+D
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Repository b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Repository
new file mode 100644
index 000000000..a8f63a18f
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Repository
@@ -0,0 +1 @@
+org.eclipse.sdk.tests-feature/plugins/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Root b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Root
new file mode 100644
index 000000000..2d37d165b
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Root
@@ -0,0 +1 @@
+:pserver:anonymous@dev.eclipse.org:/cvsroot/eclipse
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Tag b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Tag
new file mode 100644
index 000000000..25d2caaa5
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/CVS/Tag
@@ -0,0 +1 @@
+Nr20080922
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/ICompareResult.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/ICompareResult.java
new file mode 100755
index 000000000..0263956bb
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/ICompareResult.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.versioning;
+
+import org.eclipse.core.runtime.MultiStatus;
+
+/**
+ * This interface provides methods to access to compare result information of a plugin or class
+ * <p>
+ * <b>Note:</b> This interface should not be implemented by clients.
+ * </p><p>
+ * <b>Note:</b> This class/interface is part of an interim API that is still under development and expected to
+ * change significantly before reaching stability. It is being made available at this early stage to solicit feedback
+ * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken
+ * (repeatedly) as the API evolves.
+ * </p>
+ */
+public interface ICompareResult {
+ /**
+ * gets MuliStatus instance which contains messages created when verify a plugin or class
+ * @return MultiStatus instance
+ */
+ public MultiStatus getResultStatus();
+
+ /**
+ * gets overall change happened on a plugin or class
+ * <p>
+ * The value of change is an int number of the following:
+ * <ul>
+ * <li>{@link IVersionCompare#ERROR_OCCURRED}</li>
+ * <li>{@link IVersionCompare#MAJOR_CHANGE}</li>
+ * <li>{@link IVersionCompare#MINOR_CHANGE}</li>
+ * <li>{@link IVersionCompare#NEW_ADDED}</li>
+ * <li>{@link IVersionCompare#NO_LONGER_EXIST}</li>
+ * <li>{@link IVersionCompare#MICRO_CHANGE}</li>
+ * <li>{@link IVersionCompare#QUALIFIER_CHANGE}</li>
+ * <li>{@link IVersionCompare#NO_CHANGE}</li>
+ * </ul>
+ * </p>
+ * @return change int number which indicates the overall change happened on a plugin or class
+ * @see IVersionCompare#ERROR_OCCURRED
+ * @see IVersionCompare#MAJOR_CHANGE
+ * @see IVersionCompare#MINOR_CHANGE
+ * @see IVersionCompare#NEW_ADDED
+ * @see IVersionCompare#NO_LONGER_EXIST
+ * @see IVersionCompare#MICRO_CHANGE
+ * @see IVersionCompare#QUALIFIER_CHANGE
+ * @see IVersionCompare#NO_CHANGE
+ */
+ public int getChange();
+}
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/IVersionCompare.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/IVersionCompare.java
new file mode 100644
index 000000000..faf0eebde
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/IVersionCompare.java
@@ -0,0 +1,547 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.versioning;
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jdt.core.util.IClassFileReader;
+
+/**
+ * This interface provides methods to clients for verification of version numbers
+ * for features and plug-ins contained within an Eclipse configuration or under a directory.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients will use the provided
+ * factory to acquire an implementation for use.
+ * </p><p>
+ * <b>Note:</b> This class/interface is part of an interim API that is still under development and expected to
+ * change significantly before reaching stability. It is being made available at this early stage to solicit feedback
+ * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken
+ * (repeatedly) as the API evolves.
+ * </p>
+ */
+public interface IVersionCompare {
+
+ /**
+ * This String type constant is a property name in compare option file;
+ * It's value indicates exclusive feature ids.
+ */
+ public static final String EXCLUDE_FEATURES_OPTION = "exclude.features"; //$NON-NLS-1$
+
+ /**
+ * This String type constant is a property name in compare option file;
+ * It's value indicates inclusive feature ids.
+ */
+ public static final String INCLUDE_FEATURES_OPTION = "include.features"; //$NON-NLS-1$
+
+ /**
+ * This String type constant is a property name in compare option file;
+ * It's value indicates exclusive plugin ids.
+ */
+ public static final String EXCLUDE_PLUGINS_OPTION = "exclude.plugins"; //$NON-NLS-1$
+
+ /**
+ * This String type constant is a property name in compare option file;
+ * It's value indicates inclusive plugin ids.
+ */
+ public static final String INCLUDE_PLUGINS_OPTION = "include.plugins"; //$NON-NLS-1$
+
+ /**
+ * This String type constant is a property name in compare option file;
+ * It's value indicates exclusive operation systems.
+ */
+ public static final String EXCLUDE_OS_OPTION = "exclude.os"; //$NON-NLS-1$
+
+ /**
+ * This String type constant is a property name in compare option file;
+ * It's value indicates inclusive operation systems.
+ */
+ public static final String INCLUDE_OS_OPTION = "include.os"; //$NON-NLS-1$
+
+ /**
+ * This String type constant is a property name in compare option file;
+ * It's value indicates exclusive windows systems.
+ */
+ public static final String EXCLUDE_WS_OPTION = "exclude.ws"; //$NON-NLS-1$
+
+ /**
+ * This String type constant is a property name in compare option file;
+ * It's value indicates inclusive windows systems.
+ */
+ public static final String INCLUDE_WS_OPTION = "include.ws"; //$NON-NLS-1$
+
+ /**
+ * This String type constant is a property name in compare option file;
+ * It's value indicates exclusive system architecture specifications.
+ */
+ public static final String EXCLUDE_ARCH_OPTION = "exclude.arc"; //$NON-NLS-1$
+
+ /**
+ * This String type constant is a property name in compare option file;
+ * It's value indicates inclusive system architecture specifications.
+ */
+ public static final String INCLUDE_ARCH_OPTION = "include.arc"; //$NON-NLS-1$
+
+ /**
+ * This String type constant is a property name in compare option file;
+ * It's value indicates exclusive locale language specifications.
+ */
+ public static final String EXCLUDE_NL_OPTION = "exclude.nl"; //$NON-NLS-1$
+
+ /**
+ * This String type constant is a property name in compare option file;
+ * It's value indicates inclusive locale language specifications
+ */
+ public static final String INCLUDE_NL_OPTION = "include.nl"; //$NON-NLS-1$
+
+ /**
+ * This int type constant indicates overall compare result of a feature
+ */
+ public static final int FEATURE_OVERALL_STATUS = 0x0001;
+
+ /**
+ * This int type constant indicates detail compare messages of a feature
+ */
+ public static final int FEATURE_DETAIL_STATUS = 0x0002;
+
+ /**
+ * This int type constant indicates overall compare result of a plugin
+ */
+ public static final int PLUGIN_OVERALL_STATUS = 0x0004;
+
+ /**
+ * This int type constant indicates detail compare messages of a plugin
+ */
+ public static final int PLUGIN_DETAIL_STATUS = 0x0008;
+
+ /**
+ * This int type constant indicates overall compare result of a class
+ */
+ public static final int CLASS_OVERALL_STATUS = 0x0010;
+
+ /**
+ * This int type constant indicates detail compare messages of a class
+ */
+ public static final int CLASS_DETAIL_STATUS = 0x0020;
+
+ /**
+ * This int type constant indicates process error messages (e.g. IO error)
+ */
+ public static final int PROCESS_ERROR_STATUS = 0x0040;
+
+ /**
+ * This int type constant is a compare result of feature, plugin, class;
+ * It indicates some error occurred during comparing
+ */
+ public final static int ERROR_OCCURRED = 0x0080;
+
+ /**
+ * This int type constant is a compare result of feature, plugin, class;
+ * It indicates a major change of a feature, plugin, or class
+ */
+ public final static int MAJOR_CHANGE = 0x0100;
+
+ /**
+ * This int type constant is a compare result of feature, plugin, class;
+ * It indicates a minor change of a feature, plugin, or class
+ */
+ public final static int MINOR_CHANGE = 0x0200;
+
+ /**
+ * This int type constant is a compare result of feature, plugin, class;
+ * It indicates there is one or more new added attribute in a feature, plugin, or class
+ */
+ public final static int NEW_ADDED = 0x0400;
+
+ /**
+ * This int type constant is a compare result of feature, plugin, class;
+ * It indicates there is one or more attribute have been deleted from a feature, plugin, or class
+ */
+ public final static int NO_LONGER_EXIST = 0x0800;
+
+ /**
+ * This int type constant is a compare result of feature, plugin, class;
+ * It indicates a minor change of a feature, plugin, or class
+ */
+ public final static int MICRO_CHANGE = 0x1000;
+
+ /**
+ * This int type constant is a compare result of feature, plugin, class;
+ * It indicates a qualifier change of a feature, plugin, or class
+ */
+ public final static int QUALIFIER_CHANGE = 0x2000;
+
+ /**
+ * This int type constant is a compare result of feature, plugin, class;
+ * It indicates no change in a feature, plugin, or class
+ */
+ public final static int NO_CHANGE = 0x4000;
+
+ /**
+ * Verify two sets of features and return a status object indicating whether or not the version numbers
+ * of the features (an optionally of their included plug-ins) have been incremented appropriated based
+ * on the changes between the two sets.
+ * <p>
+ * Feature Version update priority:
+ * Versions have four parts: major, minor, micro, and qualifier.
+ * There are four corresponding kinds of version update: major update,
+ * minor update, micro update, qualifier update. Besides, there are two
+ * other kinds of update: new_added update(if some features or plugins
+ * have been new added to the feature), and no_longer_exist update(if
+ * some features or plugins have been deleted from the feature). Consequently,
+ * major update has the highest priority, then minor update (currently
+ * new_added and no_longer_exist are considered as minor updates), then
+ * micro update, and qualifier update has the lowest priority. If we talk
+ * about version update of a feature or a plugin, we mean the update with
+ * the highest priority.
+ * </p><p>
+ * Feature Version update rule:
+ * Usually, a feature includes other features and plug-ins,
+ * e.g. :
+ * old version of "f1":
+ * <pre>
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <feature id="f1" label="aaa" version="1.0.0.v2005">
+ * <includes id="f2" version="1.0.0.v2005" name="bbb"/>
+ * <includes id="f3" version="1.0.0.v2005" name="ccc"/>
+ * <plugin id="p1" version="1.0.0.v2005"/>
+ * <plugin id="p2" version="1.0.0.v2005"/>
+ * <plugin id="p3" version="1.0.0.v2005"/>
+ * </feature>
+ * </pre>
+ * new version of "f1":
+ * <pre>
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <feature id="f1" label="aaa" version="3.0.0">
+ * <includes id="f2" version="2.0.0.v2005" name="bbb"/>
+ * <includes id="f3" version="1.1.0.v2005" name="ccc"/>
+ * <plugin id="p1" version="1.0.1.v2005"/>
+ * <plugin id="p2" version="1.0.0.v2006"/>
+ * <plugin id="p4" version="1.0.0.v2006"/>
+ * </feature>
+ * </pre></p><p>
+ * The basic rule of version update is that if we have updated versions of
+ * any include features(f2,f3) or plugins(p1,p2), we need to update the version
+ * of f1. Update of f1 should be at least the highest update of its included
+ * features and plug-ins. For instance, "f2" has a major update, "f3" has a minor
+ * update, "p1" has a micro update, and "p2" has a qualifier update, "p3" no
+ * longer exists in "f1", "p4" has been new added to "f1". In conclusion, "f1"
+ * should at least have a major change(it's ok if "f1" also has a minor, micro,
+ * or qualifier update).
+ * </p><p>
+ * Feature Verification process:
+ * To verify the new version of "f1", we need to compare its included features
+ * and plug-ins with those included in its old version and find out the update
+ * with the highest priority. For included features, such as "f2" and "f3", before
+ * comparing them with their corresponding ones in old "f1", we need to verify
+ * their new versions first through recursion, and then,
+ * <ul>
+ * <li>if the new versions of "f2" is correct, we use the new version of "f2" to
+ * compare with the version of "f2" in old "f1".
+ * <li>if the new versions of "f2" is wrong, we try to generate a recommended new
+ * version for "f2", and then,
+ *<li>if we can generate a recommended new version for "f2", we use the recommended
+ * new version to compare with the version of "f2" in old "f1".
+ * <li>if we can not generate a recommended new version for "f2", there must be
+ * some error occurred. We will create a warning message for that error and
+ * we will also create a message to tell user that "f1" can not be verified
+ * correctly, since we can't verify some of its included features. (The process
+ * will not stop if we find an error. It will continually to compare and try
+ * to find problems as more as possible, and warning messages will be collected,
+ * and displayed at last.)
+ * </ul>
+ * </p><p>
+ * We must increment the major part if:
+ * <ul>
+ * <li>an included feature has incremented the major part of its version
+ * <li>an included plug-in has incremented the major part of its version
+ * </ul>
+ * </p><p>
+ * We must increment the minor part if:
+ * <ul>
+ * <li>an included feature has incremented the minor part of its version
+ * <li>an included plug-in has incremented the minor part of its version
+ * <li>if a new plug-in was added to the feature
+ * <li>if a plug-in was removed from the feature
+ * <li>if a new included feature was added to the feature
+ * <li>if an included feature was removed from the feature
+ * </ul>
+ * </p><p>
+ * We must increment the micro part if:
+ * <ul>
+ * <li>an included feature has incremented the micro part of its version
+ * <li>an included plug-in has incremented the micro part of its version
+ * </ul>
+ * </p><p>
+ * We must increment the qualifier if:
+ * <ul>
+ * <li>an included feature has incremented the qualifier part of its version
+ * <li>an included plug-in has incremented the qualifier part of its version
+ * </ul>
+ * </p>
+ *
+ * @param file1 File instance which denotes a configuration file or a feature directory
+ * @param file2 File instance which denotes a configuration file or a feature directory
+ * @param needPluginCompare if <code>true</code>, the method will compare plugin objects; if <code>false</code>
+ * it just compares plugin names and versions.
+ * @return IStatus instance which contains child status. Each child status indicates
+ * an error or warning of one included feature or plug-in
+ * @param compareOptionFile a property file which indicates exclusion and inclusion for feature compare
+ * @param monitor IProgressMonitor instance which will monitor the progress during feature comparing
+ * @throws CoreException
+ * @see #checkFeatureVersions(String, String, boolean, File, IProgressMonitor)
+ * @see #checkFeatureVersions(URL, URL, boolean, File, IProgressMonitor)
+ */
+ public IStatus checkFeatureVersions(File file1, File file2, boolean needPluginCompare, File compareOptionFile, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * As per {@link #checkFeatureVersions(File, File, boolean, File, IProgressMonitor)} except the given parameters are strings
+ * pointing to the configuration file or features directory.
+ *
+ * @param path1 path which denotes an eclipse configuration XML file or a feature directory
+ * @param path2 path which denotes an eclipse configuration XML file or a feature directory
+ * @param needPluginCompare if <code>true</code>, the method will compare plugin objects; if <code>false</code>
+ * it just compares plugin names and versions.
+ * @param compareOptionFile a property file which indicates exclusion and inclusion for feature compare
+ * @param monitor IProgressMonitor instance which will monitor the progress during feature comparing
+ * @return a status containing the comparison result
+ * @throws CoreException
+ * @see #checkFeatureVersions(File, File, boolean, File, IProgressMonitor)
+ * @see #checkFeatureVersions(URL, URL, boolean, File, IProgressMonitor)
+ */
+ public IStatus checkFeatureVersions(String path1, String path2, boolean needPluginCompare, File compareOptionFile, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * As per {@link #checkFeatureVersions(File, File, boolean, File, IProgressMonitor)} except the given parameters are urls
+ * pointing to configuration files.
+ *
+ * @param configURL1 reference to an eclipse configuration XML file
+ * @param configURL2 reference to an eclipse configuration XML file
+ * @param needPluginCompare if <code>true</code>, the method will compare plugin objects; if <code>false</code>
+ * it just compares plugin names and versions.
+ * @param compareOptionFile a property file which indicates exclusion and inclusion for feature compare
+ * @param monitor IProgressMonitor instance which will monitor the progress during feature comparing
+ * @return a status containing the comparison result
+ * @throws CoreException
+ * @see #checkFeatureVersions(File, File, boolean, File, IProgressMonitor)
+ * @see #checkFeatureVersions(String, String, boolean, File, IProgressMonitor)
+ */
+ public IStatus checkFeatureVersions(URL configURL1, URL configURL2, boolean needPluginCompare, File compareOptionFile, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * <p>
+ * Compares the two given Java class files and returns a ICompareResult object containing a summary
+ * of the changes between the two files.
+ * </P><p>
+ * Steps to compare two classes:
+ * <ul>
+ * <li>1. compares class names. If two classes do not have the same class name, we don't do
+ * further compare.</li>
+ * <li>2. compares class modifiers.
+ * <ul>
+ * <li>A. If the modifier of a class has been changed from public to non-public</li>
+ * or from protected to modifier other than public and protected, it is a major change.</li>
+ * <li>B. If the modifier of a class has been changed from non-abstract to abstract, it is a major change.</li>
+ * <li>C. If the modifier of a class has been changed from non-final to final, it is a major change.</li></ul>
+ * </li>
+ * <li>3. compares super classes. If the super class has been changed, it is a major change.</li>
+ * <li>4. compares implemented interfaces. If implemented interfaces have been changed, it is a major change.</li>
+ * <li>5. compares fields.
+ * <ul>
+ * <li>A. If the modifier of a field has been changed from public to non-public
+ * or from protected to modifier other than public and protected, it is a major change.</li>
+ * <li>B. If the modifier of a field has been changed from non-final to final, it is a major change.</li>
+ * <li>C. If the modifier of a field has been changed from static to non-static, it is a major change.</li>
+ * <li>D. If the modifier of a field has been changed from volatile to non-volatile or vis-verser, it is a major change.</li>
+ * <li>E. If a public or protected field has been deprecated, it is a micro change.</li>
+ * <li>F. If a public or protected field has been new added into the class, it is a minor change.</li>
+ * <li>G. If a public or protected field has been deleted from the class, it is a major change.</li>
+ * <li>H. If the type of a field has been changed, it is a major change.</li>
+ * </ul>
+ * <li>6. compares methods.
+ * <ul>
+ * <li>A. If the modifier of a method has been changed from public to non-public
+ * or from protected to modifier other than public and protected, it is a major change.</li>
+ * <li>B. If the modifier of a method has been changed from non-abstract to abstract, it is a major change.</li>
+ * <li>C. If the modifier of a method has been changed from non-final to final, it is a major change.</li>
+ * <li>D. If the modifier of a method has been changed from static to non-static, it is a major change.</li>
+ * <li>E. If the modifier of a method has been changed from volatile to non-volatile or vis-verser, it is a major change.</li>
+ * <li>F. If a public or protected method has been deprecated, it is a micro change.</li>
+ * <li>G. If a public or protected method has been new added into the class, it is a minor change.</li>
+ * <li>H. If a public or protected method has been deleted from the class, it is a major change.</li>
+ * <li>I. If return type, number of args, or any type of args has been changed, it is considered
+ * as the combination of a method has been deleted and a new method has been added(major change).</li>
+ * <li>J. If thrown exceptions of a method have been changed, it is a minor change.</li>
+ * </ul>
+ * </li>
+ * </ul></p>
+ *
+ * @param javaClass1 Sting which denotes the full path of a java class file
+ * @param javaClass2 Sting which denotes the full path of a java class file
+ * @param monitor IProgressMonitor instance which will monitor the progress during class comparing
+ * @return ICompareResult instance which contains change on the class and messages generated when class is compared
+ * @throws CoreException if there was an exception during the comparison
+ */
+ public ICompareResult checkJavaClassVersions(String javaClass1, String javaClass2, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Compares the two given Java class files and returns a ICompareResult object containing a summary
+ * of the changes between the two files.{@link #checkJavaClassVersions(String, String, IProgressMonitor)}
+ *
+ * @param javaClassURL1 URL which denotes a java class file
+ * @param javaClassURL2 URL which denotes a java class file
+ * @param monitor IProgressMonitor instance which will monitor the progress during class comparing
+ * @return ICompareResult instance which contains change on the class and messages generated when class is compared
+ * @throws CoreException if there was an exception during the comparison
+ */
+ public ICompareResult checkJavaClassVersions(URL javaClassURL1, URL javaClassURL2, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Compares the two given Java class files and returns a ICompareResult object containing a summary
+ * of the changes between the two files.{@link #checkJavaClassVersions(String, String, IProgressMonitor)}
+ *
+ * @param javaClassFile1 File which denotes a java class file
+ * @param javaClassFile2 File which denotes a java class file
+ * @param monitor IProgressMonitor instance which will monitor the progress during class comparing
+ * @return ICompareResult instance which contains change on the class and messages generated when class is compared
+ * @throws CoreException if there was an exception during the comparison
+ */
+ public ICompareResult checkJavaClassVersions(File javaClassFile1, File javaClassFile2, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Compares the two given Java class files and returns a ICompareResult object containing a summary
+ * of the changes between the two files.{@link #checkJavaClassVersions(String, String, IProgressMonitor)}
+ * <p>
+ * This method does <em>not</em> close the InputStreams and users should handle stream closure in the calling code.
+ * </p>
+ *
+ * @param javaClassInputStream1 InputStream which denotes a java class file
+ * @param javaClassInputStream2 InputStream which denotes a java class file
+ * @param monitor IProgressMonitor instance which will monitor the progress during class comparing
+ * @return ICompareResult instance which contains change on the class and messages generated when class is compared
+ * @throws CoreException if there was an exception during the comparison
+ */
+ public ICompareResult checkJavaClassVersions(InputStream javaClassInputStream1, InputStream javaClassInputStream2, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Compares the two given Java class files and returns a ICompareResult object containing a summary
+ * of the changes between the two files.{@link #checkJavaClassVersions(String, String, IProgressMonitor)}
+ *
+ * @param classFileReader1 IClassFileReader instance which denotes a java class file
+ * @param classFileReader2 IClassFileReader instance which denotes a java class file
+ * @param monitor IProgressMonitor instance which will monitor the progress during class comparing
+ * @return ICompareResult instance which contains change on the class and messages generated when class is compared
+ * @throws CoreException if there was an exception during the comparison
+ */
+ public ICompareResult checkJavaClassVersions(IClassFileReader classFileReader1, IClassFileReader classFileReader2, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * <p>
+ * Compares the two given plug-ins which each other and reports a ICompareResult object indicating
+ * whether or not the version number of the plug-ins have been incremented appropriately
+ * based on the relative changes.<p>
+ * <p>
+ * Steps to compare two plugins:
+ * <ul>
+ * <li>1. compares all classes in the class path of the plugin to check if they have any change.</li>
+ * <li>2. if a new class has been added into the plugin, it is a minor change.</li>
+ * <li>3. if a class has been deleted from the plugin, it is a major change.</li>
+ * </ul>
+ * </p>
+ * @param plugin1 String which denotes the plug-in's jar file name or directory
+ * @param plugin2 String which denotes the plug-in's jar file name or directory
+ * @param monitor IProgressMonitor instance which will monitor the progress during plugin comparing
+ * @return ICompareResult instance which contains change on the plugin and messages generated when plugin is compared
+ * @throws CoreException if an error occurred during the comparison
+ */
+ public ICompareResult checkPluginVersions(String plugin1, String plugin2, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Compares the two given plug-ins which each other and reports a ICompareResult object indicating
+ * whether or not the version number of the plug-ins have been incremented appropriately
+ * based on the relative changes.{@link #checkPluginVersions(String, String, IProgressMonitor)}
+ *
+ * @param pluginURL1 URL which denotes a plug-in's jar file name or directory
+ * @param pluginURL2 URL which denotes a plug-in's jar file name or directory
+ * @param monitor IProgressMonitor instance which will monitor the progress during plugin comparing
+ * @return ICompareResult instance which contains change on the plugin and messages generated when plugin is compared
+ * @throws CoreException if an error occurred during the comparison
+ */
+ public ICompareResult checkPluginVersions(URL pluginURL1, URL pluginURL2, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Compares the two given plug-ins which each other and reports a ICompareResult object indicating
+ * whether or not the version number of the plug-ins have been incremented appropriately
+ * based on the relative changes.{@link #checkPluginVersions(String, String, IProgressMonitor)}
+ *
+ * @param pluginFile1 File which denotes a plug-in's jar file name or directory
+ * @param pluginFile2 File which denotes a plug-in's jar file name or directory
+ * @param monitor IProgressMonitor instance which will monitor the progress during plugin comparing
+ * @return ICompareResult instance which contains change on the plugin and messages generated when plugin is compared
+ * @throws CoreException if an error occurred during the comparison
+ */
+ public ICompareResult checkPluginVersions(File pluginFile1, File pluginFile2, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Return a status object whose contents are filtered based on the given bit masks.
+ * <p>
+ * The value for <code>infoChoice</code> is an integer constructor from any combination
+ * of the following bit masks:
+ * <ul>
+ * <li>{@link #FEATURE_OVERALL_STATUS}</li>
+ * <li>{@link #FEATURE_DETAIL_STATUS}</li>
+ * <li>{@link #PLUGIN_OVERALL_STATUS}</li>
+ * <li>{@link #PLUGIN_DETAIL_STATUS}</li>
+ * <li>{@link #CLASS_OVERALL_STATUS}</li>
+ * <li>{@link #CLASS_DETAIL_STATUS}</li>
+ * <li>{@link #PROCESS_ERROR_STATUS}</li>
+ * </ul>
+ * </p>
+ *
+ * @param status IStatus instance of compare result
+ * @param infoChoice integer specifying the filter to use
+ * @see #FEATURE_OVERALL_STATUS
+ * @see #FEATURE_DETAIL_STATUS
+ * @see #PLUGIN_OVERALL_STATUS
+ * @see #PLUGIN_DETAIL_STATUS
+ * @see #CLASS_OVERALL_STATUS
+ * @see #CLASS_DETAIL_STATUS
+ * @see #PROCESS_ERROR_STATUS
+ * @return the filtered status object
+ */
+ public IStatus processCompareResult(IStatus status, int infoChoice);
+
+ /**
+ * writes out children statuses of <code>status</code> to XML file denoted by <code>fileName</code>
+ * <p>
+ * The format of the XML file is as following:
+ * <pre>
+ * <CompareResult Version="1.0">
+ * <Category Name="Error" SeverityCode="4">
+ * <Info Code="1" Message="The version of the feature "org.eclipse.rcp" should be at least "3.3.0"." />
+ * ...
+ * </Category>
+ * <Category Name="Warning" SeverityCode="2">
+ * ...
+ * </Category>
+ * <Category Name="Information" SeverityCode="1">
+ * ...
+ * </Category>
+ * </CompareResult>
+ * </pre>
+ * </p>
+ * @param status IStatus instance
+ * @param fileName String name of a XML file
+ * @throws CoreException <p>if any nested CoreException has been caught</p>
+ */
+ public void writeToXML(IStatus status, String fileName) throws CoreException;
+} \ No newline at end of file
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/VersionCompareFactory.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/VersionCompareFactory.java
new file mode 100755
index 000000000..181e009ff
--- /dev/null
+++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/versioning/VersionCompareFactory.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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 org.eclipse.pde.tools.versioning;
+
+import org.eclipse.pde.tools.internal.versioning.VersionCompareDispatcher;
+
+/**
+ * Factory class to create objects used for comparing versions.
+ * <p>
+ * This class is not intended to be sub-classed by clients.
+ * </p>
+ */
+public final class VersionCompareFactory {
+
+ /**
+ * Constructor
+ */
+ public VersionCompareFactory() {
+ super();
+ }
+
+ /**
+ * Return an instance of a class which can be used for version comparison.
+ *
+ * @return version compare class
+ */
+ public IVersionCompare getVersionCompare() {
+ return new VersionCompareDispatcher();
+ }
+
+}

Back to the top