Restored 'org.eclipse.update.core'
diff --git a/update/org.eclipse.update.core/.classpath b/update/org.eclipse.update.core/.classpath
new file mode 100644
index 0000000..b54a094
--- /dev/null
+++ b/update/org.eclipse.update.core/.classpath
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="jarprocessor"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.4"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/update/org.eclipse.update.core/.cvsignore b/update/org.eclipse.update.core/.cvsignore
new file mode 100644
index 0000000..c5e82d7
--- /dev/null
+++ b/update/org.eclipse.update.core/.cvsignore
@@ -0,0 +1 @@
+bin
\ No newline at end of file
diff --git a/update/org.eclipse.update.core/.options b/update/org.eclipse.update.core/.options
new file mode 100644
index 0000000..7bf6197
--- /dev/null
+++ b/update/org.eclipse.update.core/.options
@@ -0,0 +1,9 @@
+org.eclipse.update.core/debug=true
+org.eclipse.update.core/debug/warning=false
+org.eclipse.update.core/debug/parsing=false
+org.eclipse.update.core/debug/install=false
+org.eclipse.update.core/debug/configuration=false
+org.eclipse.update.core/debug/type=false
+org.eclipse.update.core/debug/web=false
+org.eclipse.update.core/debug/installhandler=false
+org.eclipse.update.core/debug/reconciler=false
diff --git a/update/org.eclipse.update.core/.project b/update/org.eclipse.update.core/.project
index dec3727..e358fd4 100644
--- a/update/org.eclipse.update.core/.project
+++ b/update/org.eclipse.update.core/.project
@@ -1,11 +1,26 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.eclipse.update.core</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- </buildSpec>
- <natures>
- </natures>
-</projectDescription>
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.update.core</name>
+ <comment></comment>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ </natures>
+</projectDescription>
diff --git a/update/org.eclipse.update.core/.settings/org.eclipse.jdt.core.prefs b/update/org.eclipse.update.core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..23d6e87
--- /dev/null
+++ b/update/org.eclipse.update.core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,86 @@
+#Wed Feb 11 12:06:10 EST 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=error
+org.eclipse.jdt.core.compiler.problem.deprecation=ignore
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=ignore
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=disabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=disabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=public
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=ignore
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=error
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.3
diff --git a/update/org.eclipse.update.core/META-INF/MANIFEST.MF b/update/org.eclipse.update.core/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..62ba95b
--- /dev/null
+++ b/update/org.eclipse.update.core/META-INF/MANIFEST.MF
@@ -0,0 +1,34 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.update.core; singleton:=true
+Bundle-Version: 3.2.600.qualifier
+Bundle-Activator: org.eclipse.update.internal.core.UpdateCore
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Export-Package: org.eclipse.update.configuration,
+ org.eclipse.update.core,
+ org.eclipse.update.core.model,
+ org.eclipse.update.internal.core;x-friends:="org.eclipse.update.ui,org.eclipse.update.scheduler,org.eclipse.pde.build",
+ org.eclipse.update.internal.core.connection;x-internal:=true,
+ org.eclipse.update.internal.jarprocessor;x-friends:="org.eclipse.pde.build",
+ org.eclipse.update.internal.mirror;x-internal:=true,
+ org.eclipse.update.internal.model;x-friends:="org.eclipse.update.ui",
+ org.eclipse.update.internal.operations;x-friends:="org.eclipse.update.ui,org.eclipse.update.scheduler",
+ org.eclipse.update.internal.provisional;x-internal:=true,
+ org.eclipse.update.internal.search;x-friends:="org.eclipse.update.ui",
+ org.eclipse.update.internal.security;x-internal:=true,
+ org.eclipse.update.internal.verifier;x-internal:=true,
+ org.eclipse.update.operations,
+ org.eclipse.update.search,
+ org.eclipse.update.standalone
+Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.4.0,4.0.0)",
+ org.eclipse.update.configurator;bundle-version="[3.1.0,4.0.0)",
+ org.eclipse.core.net;bundle-version="[1.0.0,2.0.0)"
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: J2SE-1.4,
+ CDC-1.1/Foundation-1.1
+Import-Package: javax.xml.parsers,
+ org.w3c.dom,
+ org.xml.sax,
+ org.xml.sax.helpers
diff --git a/update/org.eclipse.update.core/README.TXT b/update/org.eclipse.update.core/README.TXT
deleted file mode 100644
index c809c74..0000000
--- a/update/org.eclipse.update.core/README.TXT
+++ /dev/null
@@ -1,2 +0,0 @@
-This bundle is obsolete.
-Its functionality is provided by p2.
\ No newline at end of file
diff --git a/update/org.eclipse.update.core/about.html b/update/org.eclipse.update.core/about.html
new file mode 100644
index 0000000..4602330
--- /dev/null
+++ b/update/org.eclipse.update.core/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 2, 2006</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/update/org.eclipse.update.core/build.properties b/update/org.eclipse.update.core/build.properties
new file mode 100644
index 0000000..cc35d07
--- /dev/null
+++ b/update/org.eclipse.update.core/build.properties
@@ -0,0 +1,22 @@
+###############################################################################
+# Copyright (c) 2000, 2008 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
+###############################################################################
+source.. = src/,\
+ jarprocessor/
+bin.includes = plugin.xml,\
+ plugin.properties,\
+ .,\
+ about.html,\
+ .options,\
+ META-INF/
+src.includes = about.html,\
+ schema/
+output.. = bin/
+customBuildCallbacks=customBuildCallbacks.xml
diff --git a/update/org.eclipse.update.core/customBuildCallbacks.xml b/update/org.eclipse.update.core/customBuildCallbacks.xml
new file mode 100644
index 0000000..a26456f
--- /dev/null
+++ b/update/org.eclipse.update.core/customBuildCallbacks.xml
Binary files differ
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/CommandStep.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/CommandStep.java
new file mode 100644
index 0000000..39c17d3
--- /dev/null
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/CommandStep.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.jarprocessor;
+
+import java.io.File;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * @author aniefer@ca.ibm.com
+ *
+ */
+public abstract class CommandStep implements IProcessStep {
+ protected String command = null;
+ protected String extension = null;
+ private Properties options = null;
+ protected boolean verbose = false;
+
+ public CommandStep(Properties options, String command, String extension, boolean verbose) {
+ this.command = command;
+ this.extension = extension;
+ this.options = options;
+ this.verbose = verbose;
+ }
+
+ protected static int execute(String[] cmd) {
+ return execute(cmd, false);
+ }
+
+ protected static int execute(String[] cmd, boolean verbose) {
+ Runtime runtime = Runtime.getRuntime();
+ Process proc = null;
+ try {
+ proc = runtime.exec(cmd);
+ StreamProcessor errorStreamProcessor = new StreamProcessor(proc.getErrorStream(), StreamProcessor.STDERR, verbose); //$NON-NLS-1$
+ StreamProcessor outputStreamProcessor = new StreamProcessor(proc.getInputStream(), StreamProcessor.STDOUT, verbose); //$NON-NLS-1$
+ errorStreamProcessor.start();
+ outputStreamProcessor.start();
+ } catch (Exception e) {
+ if(verbose) {
+ System.out.println("Error executing command " + Utils.concat(cmd)); //$NON-NLS-1$
+ e.printStackTrace();
+ }
+ return -1;
+ }
+ try {
+ int result = proc.waitFor();
+ return result;
+ } catch (InterruptedException e) {
+ if(verbose)
+ e.printStackTrace();
+ }
+ return -1;
+ }
+
+ public Properties getOptions() {
+ if(options == null)
+ options = new Properties();
+ return options;
+ }
+
+ public void adjustInf(File input, Properties inf, List containers) {
+ //nothing
+ }
+}
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/IProcessStep.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/IProcessStep.java
new file mode 100644
index 0000000..18c438e
--- /dev/null
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/IProcessStep.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.jarprocessor;
+
+import java.io.File;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * @author aniefer@ca.ibm.com
+ *
+ */
+public interface IProcessStep {
+
+ /**
+ * The effect of this processing step if the JarProcessor was to recurse on this entry.
+ * Return null if this step will not do anything with this entry.
+ * Return the new entryName if this step will modify this entry on recursion.
+ * @param entryName
+ * @return
+ */
+ public String recursionEffect(String entryName);
+
+ /**
+ * Perform some processing on the input file before the JarProcessor considers the entries for recursion.
+ * return the file containing the result of the processing
+ * @param input
+ * @param workingDirectory
+ * @param containers: inf properties for containing jars, innermost jar is first on the list
+ * @return
+ */
+ public File preProcess(File input, File workingDirectory, List containers);
+
+ /**
+ * Perform some processing on the input file after the JarProcessor returns from recursion
+ * return the file containing the result of the processing
+ * @param input
+ * @param workingDirectory
+ * @param containers: inf properties for containing jars, innermost jar is first on the list
+ * @return
+ */
+ public File postProcess(File input, File workingDirectory, List containers);
+
+ /**
+ * Return the name of this process step
+ * @return
+ */
+ public String getStepName();
+
+ /**
+ * Adjust any properties in the eclipse.inf as appropriate for this step
+ * @param input
+ * @param inf
+ * @param containers: inf properties for containing jars, innermost jar is first on the list
+ */
+ public void adjustInf(File input, Properties inf, List containers);
+}
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/JarProcessor.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/JarProcessor.java
new file mode 100644
index 0000000..aef3704
--- /dev/null
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/JarProcessor.java
@@ -0,0 +1,393 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.jarprocessor;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+
+/**
+ * @author aniefer@ca.ibm.com
+ *
+ */
+public class JarProcessor {
+ private List steps = new ArrayList();
+ private String workingDirectory = ""; //$NON-NLS-1$
+ private int depth = -1;
+ private boolean verbose = false;
+ private boolean processAll = false;
+ private LinkedList containingInfs = new LinkedList();
+
+ static public JarProcessor getUnpackProcessor(Properties properties) {
+ if (!canPerformUnpack())
+ throw new UnsupportedOperationException();
+ JarProcessor processor = new JarProcessor();
+ processor.addProcessStep(new UnpackStep(properties));
+ return processor;
+ }
+
+ static public JarProcessor getPackProcessor(Properties properties) {
+ if (!canPerformPack())
+ throw new UnsupportedOperationException();
+ JarProcessor processor = new JarProcessor();
+ processor.addProcessStep(new PackStep(properties));
+ return processor;
+ }
+
+ static public boolean canPerformPack() {
+ return PackStep.canPack();
+ }
+
+ static public boolean canPerformUnpack() {
+ return UnpackStep.canUnpack();
+ }
+
+ public String getWorkingDirectory() {
+ return workingDirectory;
+ }
+
+ public void setWorkingDirectory(String dir) {
+ if(dir != null)
+ workingDirectory = dir;
+ }
+
+ public void setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ public void setProcessAll(boolean all){
+ this.processAll = all;
+ }
+
+ public void addProcessStep(IProcessStep step) {
+ steps.add(step);
+ }
+
+ public void clearProcessSteps() {
+ steps.clear();
+ }
+
+ /**
+ * Recreate a jar file. The replacements map specifies entry names to be replaced, the replacements are
+ * expected to be found in directory.
+ *
+ * @param jar - The input jar
+ * @param outputJar - the output
+ * @param replacements - map of entryName -> new entryName
+ * @param directory - location to find file for new entryName
+ * @throws IOException
+ */
+ private void recreateJar(JarFile jar, JarOutputStream outputJar, Map replacements, File directory, Properties inf) throws IOException {
+ InputStream in = null;
+ boolean marked = false;
+ try {
+ Enumeration entries = jar.entries();
+ for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
+ File replacement = null;
+ JarEntry newEntry = null;
+ if (replacements.containsKey(entry.getName())) {
+ String name = (String) replacements.get(entry.getName());
+ replacement = new File(directory, name);
+ if (name != null) {
+ if (replacement.exists()) {
+ try {
+ in = new BufferedInputStream(new FileInputStream(replacement));
+ newEntry = new JarEntry(name);
+ } catch (Exception e) {
+ if (verbose) {
+ e.printStackTrace();
+ System.out.println("Warning: Problem reading " +replacement.getPath() + ", using " + jar.getName() + File.separator + entry.getName() + " instead.");
+ }
+ }
+ } else if (verbose) {
+ System.out.println("Warning: " + replacement.getPath() + " not found, using " + jar.getName() + File.separator + entry.getName() + " instead.");
+ }
+ }
+ }
+ if (newEntry == null) {
+ try {
+ in = new BufferedInputStream(jar.getInputStream(entry));
+ newEntry = new JarEntry(entry.getName());
+ } catch( Exception e ) {
+ if(verbose) {
+ e.printStackTrace();
+ System.out.println("ERROR: problem reading " + entry.getName() + " from " + jar.getName());
+ }
+ continue;
+ }
+ }
+ newEntry.setTime(entry.getTime());
+ outputJar.putNextEntry(newEntry);
+ if (entry.getName().equals(Utils.MARK_FILE_NAME)) {
+ //The eclipse.inf file was read in earlier, don't need to reread it, just write it out now
+ Utils.storeProperties(inf, outputJar);
+ marked = true;
+ } else {
+ Utils.transferStreams(in, outputJar, false);
+ }
+ outputJar.closeEntry();
+ in.close();
+
+ //delete the nested jar file
+ if (replacement != null) {
+ replacement.delete();
+ }
+ }
+ if (!marked) {
+ JarEntry entry = new JarEntry(Utils.MARK_FILE_NAME);
+ outputJar.putNextEntry(entry);
+ Utils.storeProperties(inf, outputJar);
+ outputJar.closeEntry();
+ }
+ } finally {
+ Utils.close(outputJar);
+ Utils.close(jar);
+ Utils.close(in);
+ }
+ }
+
+ private String recursionEffect(String entryName) {
+ String result = null;
+ for (Iterator iter = steps.iterator(); iter.hasNext();) {
+ IProcessStep step = (IProcessStep) iter.next();
+
+ result = step.recursionEffect(entryName);
+ if (result != null)
+ entryName = result;
+ }
+ return result;
+ }
+
+ private void extractEntries(JarFile jar, File tempDir, Map data, Properties inf) throws IOException {
+ if(inf != null ) {
+ //skip if excluding children
+ if(inf.containsKey(Utils.MARK_EXCLUDE_CHILDREN)){
+ String excludeChildren = inf.getProperty(Utils.MARK_EXCLUDE_CHILDREN);
+ if( Boolean.valueOf(excludeChildren).booleanValue() )
+ if(verbose){
+ for(int i = 0; i <= depth; i++)
+ System.out.print(" "); //$NON-NLS-1$
+ System.out.println("Children of " + jar.getName() + "are excluded from processing.");
+ }
+ return;
+ }
+ }
+
+ Enumeration entries = jar.entries();
+ if (entries.hasMoreElements()) {
+ for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
+ String name = entry.getName();
+ String newName = recursionEffect(name);
+ if (newName != null) {
+ if(verbose){
+ for(int i = 0; i <= depth; i++)
+ System.out.print(" "); //$NON-NLS-1$
+ System.out.println("Processing nested file: " + name); //$NON-NLS-1$
+ }
+ //extract entry to temp directory
+ File extracted = new File(tempDir, name);
+ File parentDir = extracted.getParentFile();
+ if (!parentDir.exists())
+ parentDir.mkdirs();
+
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ in = jar.getInputStream(entry);
+ out = new BufferedOutputStream(new FileOutputStream(extracted));
+ Utils.transferStreams(in, out, true); //this will close both streams
+ } finally {
+ Utils.close(in);
+ Utils.close(out);
+ }
+ extracted.setLastModified(entry.getTime());
+
+ //recurse
+ containingInfs.addFirst(inf);
+ String dir = getWorkingDirectory();
+ setWorkingDirectory(parentDir.getCanonicalPath());
+ File result = processJar(extracted);
+
+ newName = name.substring(0, name.length() - extracted.getName().length()) + result.getName();
+ data.put(name, newName);
+
+ setWorkingDirectory(dir);
+ containingInfs.removeFirst();
+
+ //delete the extracted item leaving the recursion result
+ if (!name.equals(newName))
+ extracted.delete();
+ }
+ }
+ }
+ }
+
+ private File preProcess(File input, File tempDir) {
+ File result = null;
+ for (Iterator iter = steps.iterator(); iter.hasNext();) {
+ IProcessStep step = (IProcessStep) iter.next();
+ result = step.preProcess(input, tempDir, containingInfs);
+ if (result != null)
+ input = result;
+ }
+ return input;
+ }
+
+ private File postProcess(File input, File tempDir) {
+ File result = null;
+ for (Iterator iter = steps.iterator(); iter.hasNext();) {
+ IProcessStep step = (IProcessStep) iter.next();
+ result = step.postProcess(input, tempDir, containingInfs);
+ if (result != null)
+ input = result;
+ }
+ return input;
+ }
+
+ private void adjustInf(File input, Properties inf) {
+ for (Iterator iter = steps.iterator(); iter.hasNext();) {
+ IProcessStep step = (IProcessStep) iter.next();
+ step.adjustInf(input, inf, containingInfs);
+ }
+ }
+
+ public File processJar(File input) throws IOException {
+ ++depth;
+ long lastModified = input.lastModified();
+ File workingDir = new File(getWorkingDirectory());
+ if (!workingDir.exists())
+ workingDir.mkdirs();
+
+ boolean skip = Utils.shouldSkipJar(input, processAll, verbose);
+ if (depth == 0 && verbose) {
+ if (skip)
+ System.out.println("Skipping " + input.getPath()); //$NON-NLS-1$
+ else {
+ System.out.print("Running "); //$NON-NLS-1$
+ for (Iterator iter = steps.iterator(); iter.hasNext();) {
+ IProcessStep step = (IProcessStep) iter.next();
+ System.out.print(step.getStepName() + " "); //$NON-NLS-1$
+ }
+ System.out.println("on " + input.getPath()); //$NON-NLS-1$
+ }
+ }
+
+ if (skip) {
+ //This jar was not marked as conditioned, and we are only processing conditioned jars, so do nothing
+ --depth;
+ return input;
+ }
+
+ //pre
+ File workingFile = preProcess(input, workingDir);
+
+ //Extract entries from jar and recurse on them
+ File tempDir = null;
+ if (depth == 0) {
+ tempDir = new File(workingDir, "temp." + workingFile.getName()); //$NON-NLS-1$
+ } else {
+ File parent = workingDir.getParentFile();
+ tempDir = new File(parent, "temp_" + depth + '_' + workingFile.getName()); //$NON-NLS-1$
+ }
+
+ JarFile jar = new JarFile(workingFile, false);
+ Map replacements = new HashMap();
+ Properties inf = Utils.getEclipseInf(workingFile, verbose);
+ extractEntries(jar, tempDir, replacements, inf);
+
+ if (inf != null)
+ adjustInf(workingFile, inf);
+
+ //Recreate the jar with replacements.
+ //TODO: This is not strictly necessary if we didn't change the inf file and didn't change any content
+ File tempJar = null;
+ tempJar = new File(tempDir, workingFile.getName());
+ File parent = tempJar.getParentFile();
+ if (!parent.exists())
+ parent.mkdirs();
+ JarOutputStream jarOut = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(tempJar)));
+ recreateJar(jar, jarOut, replacements, tempDir, inf);
+
+ jar.close();
+ if (tempJar != null) {
+ if (!workingFile.equals(input)) {
+ workingFile.delete();
+ }
+ workingFile = tempJar;
+ }
+
+ //post
+ File result = postProcess(workingFile, workingDir);
+
+ //have to normalize after the post steps
+ normalize(result, workingDir);
+
+ if (!result.equals(workingFile) && !workingFile.equals(input))
+ workingFile.delete();
+ if (!result.getParentFile().equals(workingDir)) {
+ File finalFile = new File(workingDir, result.getName());
+ if (finalFile.exists())
+ finalFile.delete();
+ result.renameTo(finalFile);
+ result = finalFile;
+ }
+
+ if (tempDir.exists())
+ Utils.clear(tempDir);
+
+ result.setLastModified(lastModified);
+ --depth;
+ return result;
+ }
+
+ private void normalize(File input, File workingDirectory) {
+ if(input.getName().endsWith(Utils.PACKED_SUFFIX)) {
+ //not a jar
+ return;
+ }
+ try {
+ File tempJar = new File(workingDirectory, "temp_" + input.getName()); //$NON-NLS-1$
+ JarFile jar = null;
+ try {
+ jar = new JarFile(input, false);
+ } catch (JarException e) {
+ //not a jar
+ return ;
+ }
+ JarOutputStream jarOut = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(tempJar)));
+ InputStream in = null;
+ try {
+ Enumeration entries = jar.entries();
+ for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
+ JarEntry newEntry = new JarEntry(entry.getName());
+ newEntry.setTime(entry.getTime());
+ in = new BufferedInputStream(jar.getInputStream(entry));
+ jarOut.putNextEntry(newEntry);
+ Utils.transferStreams(in, jarOut, false);
+ jarOut.closeEntry();
+ in.close();
+ }
+ } finally {
+ Utils.close(jarOut);
+ Utils.close(jar);
+ Utils.close(in);
+ }
+ tempJar.setLastModified(input.lastModified());
+ input.delete();
+ tempJar.renameTo(input);
+ } catch (IOException e) {
+ if (verbose) {
+ System.out.println("Error normalizing jar " + input.getName()); //$NON-NLS-1$
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/JarProcessorExecutor.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/JarProcessorExecutor.java
new file mode 100644
index 0000000..160785d
--- /dev/null
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/JarProcessorExecutor.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.update.internal.jarprocessor;
+
+import java.io.*;
+import java.util.Properties;
+import java.util.zip.ZipException;
+import org.eclipse.update.internal.jarprocessor.Main.Options;
+
+public class JarProcessorExecutor {
+ public void runJarProcessor(Options options) {
+ if (options.input.isFile() && options.input.getName().endsWith(".zip")) { //$NON-NLS-1$
+ ZipProcessor processor = new ZipProcessor();
+ processor.setWorkingDirectory(options.outputDir);
+ processor.setSignCommand(options.signCommand);
+ processor.setPack(options.pack);
+ processor.setRepack(options.repack || (options.pack && options.signCommand != null));
+ processor.setUnpack(options.unpack);
+ processor.setVerbose(options.verbose);
+ processor.setProcessAll(options.processAll);
+ try {
+ processor.processZip(options.input);
+ } catch (ZipException e) {
+ if (options.verbose)
+ e.printStackTrace();
+ } catch (IOException e) {
+ if (options.verbose)
+ e.printStackTrace();
+ }
+ } else {
+ JarProcessor processor = new JarProcessor();
+ JarProcessor packProcessor = null;
+
+ processor.setWorkingDirectory(options.outputDir);
+ processor.setProcessAll(options.processAll);
+ processor.setVerbose(options.verbose);
+
+ //load options file
+ Properties properties = new Properties();
+ if (options.input.isDirectory()) {
+ File packProperties = new File(options.input, "pack.properties");
+ if (packProperties.exists() && packProperties.isFile()) {
+ InputStream in = null;
+ try {
+ in = new BufferedInputStream(new FileInputStream(packProperties));
+ properties.load(in);
+ } catch (IOException e) {
+ if (options.verbose)
+ e.printStackTrace();
+ } finally {
+ Utils.close(in);
+ }
+ }
+ }
+
+ if (options.unpack)
+ addUnpackStep(processor, properties, options);
+
+ if (options.repack || (options.pack && options.signCommand != null))
+ addPackUnpackStep(processor, properties, options);
+
+ if (options.signCommand != null)
+ addSignStep(processor, properties, options);
+
+ if (options.pack) {
+ packProcessor = new JarProcessor();
+ packProcessor.setWorkingDirectory(options.outputDir);
+ packProcessor.setProcessAll(options.processAll);
+ packProcessor.setVerbose(options.verbose);
+ addPackStep(packProcessor, properties, options);
+ }
+
+ try {
+ process(options.input, options.unpack ? Utils.PACK_GZ_FILTER : Utils.JAR_FILTER, options.verbose, processor, packProcessor);
+ } catch (FileNotFoundException e) {
+ if (options.verbose)
+ e.printStackTrace();
+ }
+ }
+ }
+
+ protected void process(File input, FileFilter filter, boolean verbose, JarProcessor processor, JarProcessor packProcessor) throws FileNotFoundException {
+ if (!input.exists())
+ throw new FileNotFoundException();
+
+ File[] files = null;
+ if (input.isDirectory()) {
+ files = input.listFiles();
+ } else if (filter.accept(input)) {
+ files = new File[] {input};
+ }
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isDirectory()) {
+ String dir = processor.getWorkingDirectory();
+ processor.setWorkingDirectory(dir + "/" + files[i].getName()); //$NON-NLS-1$
+ if (packProcessor != null)
+ packProcessor.setWorkingDirectory(dir + "/" + files[i].getName());
+ process(files[i], filter, verbose, processor, packProcessor);
+ processor.setWorkingDirectory(dir);
+ if (packProcessor != null)
+ packProcessor.setWorkingDirectory(dir);
+ } else if (filter.accept(files[i])) {
+ try {
+ File result = processor.processJar(files[i]);
+ if (packProcessor != null && result != null && result.exists()) {
+ packProcessor.processJar(result);
+ }
+ } catch (IOException e) {
+ if (verbose)
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public void addPackUnpackStep(JarProcessor processor, Properties properties, Options options) {
+ processor.addProcessStep(new PackUnpackStep(properties, options.verbose));
+ }
+
+ public void addSignStep(JarProcessor processor, Properties properties, Options options) {
+ processor.addProcessStep(new SignCommandStep(properties, options.signCommand, options.verbose));
+ }
+
+ public void addPackStep(JarProcessor processor, Properties properties, Options options) {
+ processor.addProcessStep(new PackStep(properties, options.verbose));
+ }
+
+ public void addUnpackStep(JarProcessor processor, Properties properties, Options options) {
+ processor.addProcessStep(new UnpackStep(properties, options.verbose));
+ }
+}
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Main.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Main.java
new file mode 100644
index 0000000..43d8e0a
--- /dev/null
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Main.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2006-2007 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.jarprocessor;
+
+import java.io.File;
+
+public class Main {
+
+ public static class Options {
+ public String outputDir = "."; //$NON-NLS-1$
+ public String signCommand = null;
+ public boolean pack = false;
+ public boolean repack = false;
+ public boolean unpack = false;
+ public boolean verbose = false;
+ public boolean processAll = false;
+ public File input = null;
+ }
+
+ private static void printUsage() {
+ System.out.println("[-option ...]... input"); //$NON-NLS-1$
+ System.out.println("The following options are supported:"); //$NON-NLS-1$
+ System.out.println("-processAll process all jars, regardless of whether they were previously normalized"); //$NON-NLS-1$
+ System.out.println(" By default only normalized jars will be processed."); //$NON-NLS-1$
+ System.out.println("-repack normalize jars "); //$NON-NLS-1$
+ System.out.println("-sign <command> sign jars using <command>"); //$NON-NLS-1$
+ System.out.println("-pack pack the jars. pack and repack are redundant unless"); //$NON-NLS-1$
+ System.out.println(" sign is also specified."); //$NON-NLS-1$
+ System.out.println("-unpack unpack pack.gz files. Unpack is mutually exclusive"); //$NON-NLS-1$
+ System.out.println(" with repack, sign and pack."); //$NON-NLS-1$
+ System.out.println();
+ System.out.println("-outputDir <dir> the output directory"); //$NON-NLS-1$
+ System.out.println("-verbose verbose mode "); //$NON-NLS-1$
+ }
+
+ public static Options processArguments(String[] args) {
+ if (args.length == 0) {
+ printUsage();
+ return null;
+ }
+
+ Options options = new Options();
+ int i = 0;
+ for (; i < args.length - 1; i++) {
+ if (args[i].equals("-pack")) {//$NON-NLS-1$
+ options.pack = true;
+ } else if (args[i].equals("-unpack")) { //$NON-NLS-1$
+ options.unpack = true;
+ } else if (args[i].equals("-sign") && i < args.length - 2) { //$NON-NLS-1$
+ if (args[i + 1].startsWith("-")) { //$NON-NLS-1$
+ printUsage();
+ return null;
+ }
+ options.signCommand = args[++i];
+ } else if (args[i].equals("-repack")) { //$NON-NLS-1$
+ options.repack = true;
+ } else if (args[i].equals("-outputDir") && i < args.length - 2) { //$NON-NLS-1$
+ if (args[i + 1].startsWith("-")) { //$NON-NLS-1$
+ printUsage();
+ return null;
+ }
+ options.outputDir = args[++i];
+ } else if (args[i].equals("-verbose")) { //$NON-NLS-1$
+ options.verbose = true;
+ } else if (args[i].equals("-processAll")) { //$NON-NLS-1$
+ options.processAll = true;
+ }
+ }
+
+ options.input = new File(args[i]);
+
+ String problemMessage = null;
+ String inputName = options.input.getName();
+ if (options.unpack) {
+ if (!JarProcessor.canPerformUnpack()) {
+ problemMessage = "The unpack200 command cannot be found."; //$NON-NLS-1$
+ } else if (options.input.isFile() && !inputName.endsWith(".zip") && !inputName.endsWith(".pack.gz")) { //$NON-NLS-1$ //$NON-NLS-2$
+ problemMessage = "Input file is not a pack.gz file."; //$NON-NLS-1$
+ } else if (options.pack || options.repack || options.signCommand != null) {
+ problemMessage = "Pack, repack or sign cannot be specified with unpack."; //$NON-NLS-1$
+ }
+ } else {
+ if (options.input.isFile() && !inputName.endsWith(".zip") && !inputName.endsWith(".jar")) { //$NON-NLS-1$ //$NON-NLS-2$
+ problemMessage = "Input file is not a jar file."; //$NON-NLS-1$
+ } else if ((options.pack || options.repack) && !JarProcessor.canPerformPack()) {
+ problemMessage = "The pack200 command can not be found."; //$NON-NLS-1$
+ }
+ }
+ if(problemMessage != null){
+ System.out.println(problemMessage);
+ System.out.println();
+ printUsage();
+ return null;
+ }
+
+ return options;
+ }
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ Options options = processArguments(args);
+ if (options == null)
+ return;
+ new JarProcessorExecutor().runJarProcessor(options);
+ }
+
+}
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackStep.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackStep.java
new file mode 100644
index 0000000..4afd638
--- /dev/null
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackStep.java
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.jarprocessor;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+public class PackStep extends CommandStep {
+
+ protected static String packCommand = null;
+ private static Boolean canPack = null;
+
+ private Set exclusions = Collections.EMPTY_SET;
+
+ public static boolean canPack() {
+ if (canPack != null)
+ return canPack.booleanValue();
+
+ String[] locations = Utils.getPack200Commands("pack200"); //$NON-NLS-1$
+ if (locations == null) {
+ canPack = Boolean.FALSE;
+ packCommand = null;
+ return false;
+ }
+
+ int result;
+ for (int i = 0; i < locations.length; i++) {
+ if (locations[i] == null)
+ continue;
+ result = execute(new String[] {locations[i], "-V"}); //$NON-NLS-1$
+ if (result == 0) {
+ packCommand = locations[i];
+ canPack = Boolean.TRUE;
+ return true;
+ }
+ }
+
+ canPack = Boolean.FALSE;
+ return false;
+ }
+
+ public PackStep(Properties options) {
+ super(options, null, null, false);
+ exclusions = Utils.getPackExclusions(options);
+ }
+
+ public PackStep(Properties options, boolean verbose) {
+ super(options, null, null, verbose);
+ exclusions = Utils.getPackExclusions(options);
+ }
+
+ public String recursionEffect(String entryName) {
+ if (canPack() && entryName.endsWith(".jar") && !exclusions.contains(entryName)) { //$NON-NLS-1$
+ return entryName + Utils.PACKED_SUFFIX;
+ }
+ return null;
+ }
+
+ public File preProcess(File input, File workingDirectory, List containers) {
+ return null;
+ }
+
+ public File postProcess(File input, File workingDirectory, List containers) {
+ if (canPack() && packCommand != null) {
+ Properties inf = Utils.getEclipseInf(input, verbose);
+ if (!shouldPack(input, containers, inf))
+ return null;
+ File outputFile = new File(workingDirectory, input.getName() + Utils.PACKED_SUFFIX);
+ try {
+ String[] cmd = getCommand(input, outputFile, inf, containers);
+ int result = execute(cmd, verbose);
+ if (result != 0 && verbose)
+ System.out.println("Error: " + result + " was returned from command: " + Utils.concat(cmd)); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (IOException e) {
+ if (verbose)
+ e.printStackTrace();
+ return null;
+ }
+ return outputFile;
+ }
+ return null;
+ }
+
+ protected boolean shouldPack(File input, List containers, Properties inf) {
+ //1: exclude by containers
+ // innermost jar is first on the list, it can override outer jars
+ for (Iterator iterator = containers.iterator(); iterator.hasNext();) {
+ Properties container = (Properties) iterator.next();
+ if (container.containsKey(Utils.MARK_EXCLUDE_CHILDREN_PACK)) {
+ if (Boolean.valueOf(container.getProperty(Utils.MARK_EXCLUDE_CHILDREN_PACK)).booleanValue()) {
+ if (verbose)
+ System.out.println(input.getName() + " is excluded from pack200 by its containers.");
+ return false;
+ }
+ break;
+ }
+ }
+
+ //2: excluded by self
+ if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_PACK) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_PACK)).booleanValue()) {
+ if (verbose)
+ System.out.println("Excluding " + input.getName() + " from " + getStepName()); //$NON-NLS-1$ //$NON-NLS-2$
+ return false;
+ }
+
+ return true;
+ }
+
+ protected String[] getCommand(File input, File outputFile, Properties inf, List containers) throws IOException {
+ String[] cmd = null;
+ String arguments = getArguments(input, inf, containers);
+ if (arguments != null && arguments.length() > 0) {
+ String[] args = Utils.toStringArray(arguments, ","); //$NON-NLS-1$
+ cmd = new String[3 + args.length];
+ cmd[0] = packCommand;
+ System.arraycopy(args, 0, cmd, 1, args.length);
+ cmd[cmd.length - 2] = outputFile.getCanonicalPath();
+ cmd[cmd.length - 1] = input.getCanonicalPath();
+ } else {
+ cmd = new String[] {packCommand, outputFile.getCanonicalPath(), input.getCanonicalPath()};
+ }
+ return cmd;
+ }
+
+ protected String getArguments(File input, Properties inf, List containers) {
+ //1: Explicitly marked in our .inf file
+ if (inf != null && inf.containsKey(Utils.PACK_ARGS)) {
+ return inf.getProperty(Utils.PACK_ARGS);
+ }
+
+ //2: Defaults set in one of our containing jars
+ for (Iterator iterator = containers.iterator(); iterator.hasNext();) {
+ Properties container = (Properties) iterator.next();
+ if (container.containsKey(Utils.DEFAULT_PACK_ARGS)) {
+ return container.getProperty(Utils.DEFAULT_PACK_ARGS);
+ }
+ }
+
+ //3: Set by name in outside pack.properties file
+ Properties options = getOptions();
+ String argsKey = input.getName() + Utils.PACK_ARGS_SUFFIX;
+ if (options.containsKey(argsKey)) {
+ return options.getProperty(argsKey);
+ }
+
+ //4: Set by default in outside pack.properties file
+ if (options.containsKey(Utils.DEFAULT_PACK_ARGS)) {
+ return options.getProperty(Utils.DEFAULT_PACK_ARGS);
+ }
+
+ return ""; //$NON-NLS-1$
+ }
+
+ public String getStepName() {
+ return "Pack"; //$NON-NLS-1$
+ }
+
+ public void adjustInf(File input, Properties inf, List containers) {
+ if (input == null || inf == null)
+ return;
+
+ //don't be verbose to check if we should mark the inf
+ boolean v = verbose;
+ verbose = false;
+ if (!shouldPack(input, containers, inf)) {
+ verbose = v;
+ return;
+ }
+ verbose = v;
+
+ //mark as conditioned if not previously marked. A signed jar is assumed to be previously conditioned.
+ if (inf.getProperty(Utils.MARK_PROPERTY) == null) {
+ inf.put(Utils.MARK_PROPERTY, "true"); //$NON-NLS-1$
+
+ //record arguments used
+ String arguments = inf.getProperty(Utils.PACK_ARGS);
+ if (arguments == null) {
+ arguments = getArguments(input, inf, containers);
+ if (arguments != null && arguments.length() > 0)
+ inf.put(Utils.PACK_ARGS, arguments);
+ }
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackUnpackStep.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackUnpackStep.java
new file mode 100644
index 0000000..019812b
--- /dev/null
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackUnpackStep.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.jarprocessor;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * @author aniefer@ca.ibm.com
+ *
+ */
+public class PackUnpackStep extends PackStep {
+ private Set exclusions = null;
+
+ public PackUnpackStep(Properties options) {
+ super(options);
+ exclusions = Utils.getPackExclusions(options);
+ }
+
+ public PackUnpackStep(Properties options, boolean verbose) {
+ super(options, verbose);
+ exclusions = Utils.getPackExclusions(options);
+ }
+
+ public String recursionEffect(String entryName) {
+ if (canPack() && entryName.endsWith(".jar") && !exclusions.contains(entryName)) { //$NON-NLS-1$
+ return entryName;
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.internal.jarprocessor.PackStep#postProcess(java.io.File, java.io.File, java.util.LinkedList)
+ */
+ public File postProcess(File input, File workingDirectory, List containers) {
+ if (canPack() && packCommand != null && input != null) {
+ Properties inf = Utils.getEclipseInf(input, verbose);
+ if (!shouldPack(input, containers, inf))
+ return null;
+ File tempFile = new File(workingDirectory, "temp_" + input.getName()); //$NON-NLS-1$
+ try {
+ String[] tmp = getCommand(input, tempFile, inf, containers);
+ String[] cmd = new String[tmp.length + 1];
+ cmd[0] = tmp[0];
+ cmd[1] = "-r"; //$NON-NLS-1$
+ System.arraycopy(tmp, 1, cmd, 2, tmp.length - 1);
+
+ int result = execute(cmd, verbose);
+ if (result == 0 && tempFile.exists()) {
+ File finalFile = new File(workingDirectory, input.getName());
+ if (finalFile.exists())
+ finalFile.delete();
+ tempFile.renameTo(finalFile);
+ return finalFile;
+ } else if (verbose) {
+ System.out.println("Error: " + result + " was returned from command: " + Utils.concat(cmd)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ } catch (IOException e) {
+ if (verbose)
+ e.printStackTrace();
+ return null;
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.internal.jarprocessor.PackStep#preProcess(java.io.File, java.io.File, java.util.LinkedList)
+ */
+ public File preProcess(File input, File workingDirectory, List containers) {
+ return null;
+ }
+
+ public String getStepName() {
+ return "Repack"; //$NON-NLS-1$
+ }
+}
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/SignCommandStep.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/SignCommandStep.java
new file mode 100644
index 0000000..282ed75
--- /dev/null
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/SignCommandStep.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2006-2007 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.jarprocessor;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+public class SignCommandStep extends CommandStep {
+ private Set exclusions = null;
+
+ public SignCommandStep(Properties options, String command) {
+ super(options, command, ".jar", false); //$NON-NLS-1$
+ exclusions = Utils.getSignExclusions(options);
+ }
+
+ public SignCommandStep(Properties options, String command, boolean verbose) {
+ super(options, command, ".jar", verbose); //$NON-NLS-1$
+ exclusions = Utils.getSignExclusions(options);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.jarprocessor.IProcessStep#recursionEffect(java.lang.String)
+ */
+ public String recursionEffect(String entryName) {
+ if (entryName.endsWith(extension) && !exclusions.contains(entryName))
+ return entryName;
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.jarprocessor.IProcessStep#preProcess(java.io.File, java.io.File)
+ */
+ public File preProcess(File input, File workingDirectory, List containers) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.jarprocessor.IProcessStep#postProcess(java.io.File, java.io.File)
+ */
+ public File postProcess(File input, File workingDirectory, List containers) {
+ if (command != null && input != null && shouldSign(input, containers)) {
+ try {
+ String[] cmd = new String[] {command, input.getCanonicalPath()};
+ int result = execute(cmd, verbose);
+ if (result == 0) {
+ return input;
+ } else if (verbose) {
+ System.out.println("Error: " + result + " was returned from command: " + Utils.concat(cmd)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ } catch (IOException e) {
+ if (verbose) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return null;
+ }
+
+ public boolean shouldSign(File input, List containers) {
+ Properties inf = null;
+
+ //1: Are we excluded from signing by our parents?
+ //innermost jar is first on the list, it overrides outer jars
+ for (Iterator iterator = containers.iterator(); iterator.hasNext();) {
+ inf = (Properties) iterator.next();
+ if (inf.containsKey(Utils.MARK_EXCLUDE_CHILDREN_SIGN)){
+ if(Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_CHILDREN_SIGN)).booleanValue()) {
+ if (verbose)
+ System.out.println(input.getName() + "is excluded from signing by its containers."); //$NON-NLS-1$ //$NON-NLS-2$
+ return false;
+ }
+ break;
+ }
+ }
+
+ //2: Is this jar itself marked as exclude?
+ inf = Utils.getEclipseInf(input, verbose);
+ if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_SIGN) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_SIGN)).booleanValue()) {
+ if (verbose)
+ System.out.println("Excluding " + input.getName() + " from signing."); //$NON-NLS-1$ //$NON-NLS-2$
+ return false;
+ }
+ return true;
+ }
+
+ public String getStepName() {
+ return "Sign"; //$NON-NLS-1$
+ }
+}
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/StreamProcessor.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/StreamProcessor.java
new file mode 100644
index 0000000..e0b5c3a
--- /dev/null
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/StreamProcessor.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.jarprocessor;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class StreamProcessor extends Thread {
+ public static final String STDERR = "STDERR"; //$NON-NLS-1$
+ public static final String STDOUT = "STDOUT"; //$NON-NLS-1$
+
+ private InputStream inputStream;
+ private String name;
+ private boolean verbose;
+
+ public StreamProcessor(InputStream is, String name, boolean verbose) {
+ this.inputStream = is;
+ this.name = name;
+ this.verbose = verbose;
+ }
+
+ public void run() {
+ try {
+ InputStreamReader isr = new InputStreamReader(inputStream);
+ BufferedReader br = new BufferedReader(isr);
+ while (true) {
+ String s = br.readLine();
+ if (s == null) {
+ break;
+ }
+ if (verbose) {
+ if (STDERR.equals(name))
+ System.err.println(name + ": " + s); //$NON-NLS-1$
+ else
+ System.out.println(name + ": " + s); //$NON-NLS-1$
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/UnpackStep.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/UnpackStep.java
new file mode 100644
index 0000000..1d30dd8
--- /dev/null
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/UnpackStep.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.jarprocessor;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * @author aniefer
+ *
+ */
+public class UnpackStep extends CommandStep {
+ public static final String UNPACKER_PROPERTY = "org.eclipse.update.jarprocessor.Unpacker"; //$NON-NLS-1$
+ private static Boolean canUnpack = null;
+ private static String unpackCommand = null;
+
+ public static boolean canUnpack() {
+ if (canUnpack != null)
+ return canUnpack.booleanValue();
+
+ String[] locations = Utils.getPack200Commands("unpack200"); //$NON-NLS-1$
+ if (locations == null) {
+ canUnpack = Boolean.FALSE;
+ unpackCommand = null;
+ return false;
+ }
+
+ int result;
+ for (int i = 0; i < locations.length; i++) {
+ if (locations[i] == null)
+ continue;
+ result = execute(new String[] {locations[i], "-V"}); //$NON-NLS-1$
+ if (result == 0) {
+ unpackCommand = locations[i];
+ canUnpack = Boolean.TRUE;
+ return true;
+ }
+ }
+
+ canUnpack = Boolean.FALSE;
+ return false;
+ }
+
+ public UnpackStep(Properties options) {
+ super(options, null, null, false);
+ }
+
+ public UnpackStep(Properties options, boolean verbose) {
+ super(options, null, null, verbose);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.jarprocessor.IProcessStep#recursionEffect(java.lang.String)
+ */
+ public String recursionEffect(String entryName) {
+ if (canUnpack() && entryName.endsWith(Utils.PACKED_SUFFIX)) {
+ return entryName.substring(0, entryName.length() - Utils.PACKED_SUFFIX.length());
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.jarprocessor.IProcessStep#preProcess(java.io.File, java.io.File)
+ */
+ public File preProcess(File input, File workingDirectory, List containers) {
+ if (canUnpack() && unpackCommand != null) {
+ String name = input.getName();
+ if (name.endsWith(Utils.PACKED_SUFFIX)) {
+ name = name.substring(0, name.length() - Utils.PACKED_SUFFIX.length());
+
+ File unpacked = new File(workingDirectory, name);
+ File parent = unpacked.getParentFile();
+ if (!parent.exists())
+ parent.mkdirs();
+ try {
+ String options = getOptions().getProperty(input.getName() + ".unpack.args"); //$NON-NLS-1$
+ String[] cmd = null;
+ if (options != null) {
+ cmd = new String[] {unpackCommand, options, input.getCanonicalPath(), unpacked.getCanonicalPath()};
+ } else {
+ cmd = new String[] {unpackCommand, input.getCanonicalPath(), unpacked.getCanonicalPath()};
+ }
+ int result = execute(cmd, verbose);
+ if (result != 0 && verbose)
+ System.out.println("Error: " + result + " was returned from command: " + Utils.concat(cmd)); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (IOException e) {
+ if (verbose)
+ e.printStackTrace();
+ return null;
+ }
+ return unpacked;
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.jarprocessor.IProcessStep#postProcess(java.io.File, java.io.File)
+ */
+ public File postProcess(File input, File workingDirectory, List containers) {
+ return null;
+ }
+
+ public String getStepName() {
+ return "Unpack"; //$NON-NLS-1$
+ }
+}
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Utils.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Utils.java
new file mode 100644
index 0000000..0f4ebbf
--- /dev/null
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Utils.java
@@ -0,0 +1,326 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.jarprocessor;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+import java.util.zip.ZipException;
+
+/**
+ * @author aniefer@ca.ibm.com
+ *
+ */
+public class Utils {
+ public static final String MARK_FILE_NAME = "META-INF/eclipse.inf"; //$NON-NLS-1$
+
+ /*
+ * Properties found in outer pack.properties file
+ */
+ //comma separated list of jars to exclude from sigining
+ public static final String SIGN_EXCLUDES = "sign.excludes"; //$NON-NLS-1$
+ //comma separated list of jars to exlclude from packing
+ public static final String PACK_EXCLUDES = "pack.excludes"; //$NON-NLS-1$
+ //Suffix used when specifying arguments to use when running pack200 on a jar
+ public static final String PACK_ARGS_SUFFIX = ".pack.args"; //$NON-NLS-1$
+
+ /*
+ * Properties found in both pack.properties and eclipse.inf
+ */
+ // Default arguments to use when running pack200.
+ // Affects all jars when specified in pack.properties, affects children when specified in eclipse.inf
+ public static final String DEFAULT_PACK_ARGS = "pack200.default.args"; //$NON-NLS-1$
+
+ /*
+ * Properties found in eclipse.inf file
+ */
+ //This jar has been conditioned with pack200
+ public static final String MARK_PROPERTY = "pack200.conditioned"; //$NON-NLS-1$
+ //Exclude this jar from processing
+ public static final String MARK_EXCLUDE = "jarprocessor.exclude"; //$NON-NLS-1$
+ //Exclude this jar from pack200
+ public static final String MARK_EXCLUDE_PACK = "jarprocessor.exclude.pack"; //$NON-NLS-1$
+ //Exclude this jar from signing
+ public static final String MARK_EXCLUDE_SIGN = "jarprocessor.exclude.sign"; //$NON-NLS-1$
+ //Exclude this jar's children from processing
+ public static final String MARK_EXCLUDE_CHILDREN = "jarprocessor.exclude.children";
+ //Exclude this jar's children from pack200
+ public static final String MARK_EXCLUDE_CHILDREN_PACK = "jarprocessor.exclude.children.pack";
+ //Exclude this jar's children from signing
+ public static final String MARK_EXCLUDE_CHILDREN_SIGN = "jarprocessor.exclude.children.sign";
+ //Arguments used in pack200 for this jar
+ public static final String PACK_ARGS = "pack200.args"; //$NON-NLS-1$
+
+ public static final String PACK200_PROPERTY = "org.eclipse.update.jarprocessor.pack200"; //$NON-NLS-1$
+ public static final String JRE = "@jre"; //$NON-NLS-1$
+ public static final String PATH = "@path"; //$NON-NLS-1$
+ public static final String NONE = "@none"; //$NON-NLS-1$
+
+ public static final String PACKED_SUFFIX = ".pack.gz"; //$NON-NLS-1$
+ public static final String JAR_SUFFIX = ".jar"; //$NON-NLS-1$
+
+ public static final FileFilter JAR_FILTER = new FileFilter() {
+ public boolean accept(File pathname) {
+ return pathname.isFile() && pathname.getName().endsWith(".jar"); //$NON-NLS-1$
+ }
+ };
+
+ public static final FileFilter PACK_GZ_FILTER = new FileFilter() {
+ public boolean accept(File pathname) {
+ return pathname.isFile() && pathname.getName().endsWith(PACKED_SUFFIX);
+ }
+ };
+
+ public static void close(Object stream) {
+ if (stream != null) {
+ try {
+ if (stream instanceof InputStream)
+ ((InputStream) stream).close();
+ else if (stream instanceof OutputStream)
+ ((OutputStream) stream).close();
+ else if (stream instanceof JarFile)
+ ((JarFile) stream).close();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+ }
+
+ /**
+ * get the set of commands to try to execute pack/unpack
+ * @param cmd, the command, either "pack200" or "unpack200"
+ * @return String [] or null
+ */
+ public static String[] getPack200Commands(String cmd) {
+ String[] locations = null;
+ String prop = System.getProperty(PACK200_PROPERTY);
+ String javaHome = System.getProperty("java.home"); //$NON-NLS-1$
+ if (NONE.equals(prop)) {
+ return null;
+ } else if (JRE.equals(prop)) {
+ locations = new String[] {javaHome + "/bin/" + cmd}; //$NON-NLS-1$
+ } else if (PATH.equals(prop)) {
+ locations = new String[] {cmd};
+ } else if (prop == null) {
+ locations = new String[] {javaHome + "/bin/" + cmd, cmd}; //$NON-NLS-1$
+ } else {
+ locations = new String[] {prop + "/" + cmd}; //$NON-NLS-1$
+ }
+ return locations;
+ }
+
+ /**
+ * Transfers all available bytes from the given input stream to the given
+ * output stream. Closes both streams if close == true, regardless of failure.
+ * Flushes the destination stream if close == false
+ *
+ * @param source
+ * @param destination
+ * @param close
+ * @throws IOException
+ */
+ public static void transferStreams(InputStream source, OutputStream destination, boolean close) throws IOException {
+ source = new BufferedInputStream(source);
+ destination = new BufferedOutputStream(destination);
+ try {
+ byte[] buffer = new byte[8192];
+ while (true) {
+ int bytesRead = -1;
+ if ((bytesRead = source.read(buffer)) == -1)
+ break;
+ destination.write(buffer, 0, bytesRead);
+ }
+ } finally {
+ if (close) {
+ close(source);
+ close(destination);
+ } else {
+ destination.flush();
+ }
+ }
+ }
+
+ /**
+ * Deletes all the files and directories from the given root down (inclusive).
+ * Returns false if we could not delete some file or an exception occurred
+ * at any point in the deletion.
+ * Even if an exception occurs, a best effort is made to continue deleting.
+ */
+ public static boolean clear(java.io.File root) {
+ boolean result = clearChildren(root);
+ try {
+ if (root.exists())
+ result &= root.delete();
+ } catch (Exception e) {
+ result = false;
+ }
+ return result;
+ }
+
+ /**
+ * Deletes all the files and directories from the given root down, except for
+ * the root itself.
+ * Returns false if we could not delete some file or an exception occurred
+ * at any point in the deletion.
+ * Even if an exception occurs, a best effort is made to continue deleting.
+ */
+ public static boolean clearChildren(java.io.File root) {
+ boolean result = true;
+ if (root.isDirectory()) {
+ String[] list = root.list();
+ // for some unknown reason, list() can return null.
+ // Just skip the children If it does.
+ if (list != null)
+ for (int i = 0; i < list.length; i++)
+ result &= clear(new java.io.File(root, list[i]));
+ }
+ return result;
+ }
+
+ public static Set getPackExclusions(Properties properties) {
+ if (properties == null)
+ return Collections.EMPTY_SET;
+
+ String packExcludes = properties.getProperty(PACK_EXCLUDES);
+ if (packExcludes != null) {
+ String[] excludes = toStringArray(packExcludes, ","); //$NON-NLS-1$
+ Set packExclusions = new HashSet();
+ for (int i = 0; i < excludes.length; i++) {
+ packExclusions.add(excludes[i]);
+ }
+ return packExclusions;
+ }
+ return Collections.EMPTY_SET;
+ }
+
+ public static Set getSignExclusions(Properties properties) {
+ if (properties == null)
+ return Collections.EMPTY_SET;
+ String signExcludes = properties.getProperty(SIGN_EXCLUDES);
+ if (signExcludes != null) {
+ String[] excludes = toStringArray(signExcludes, ","); //$NON-NLS-1$
+ Set signExclusions = new HashSet();
+ for (int i = 0; i < excludes.length; i++) {
+ signExclusions.add(excludes[i]);
+ }
+ return signExclusions;
+ }
+ return Collections.EMPTY_SET;
+ }
+
+ public static String concat(String[] array) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < array.length; i++) {
+ if (i > 0)
+ buffer.append(' ');
+ buffer.append(array[i]);
+ }
+ return buffer.toString();
+ }
+
+ public static String[] toStringArray(String input, String separator) {
+ StringTokenizer tokenizer = new StringTokenizer(input, separator);
+ int count = tokenizer.countTokens();
+ String[] result = new String[count];
+ for (int i = 0; i < count; i++) {
+ result[i] = tokenizer.nextToken().trim();
+ }
+ return result;
+ }
+
+ /**
+ * Get the properties from the eclipse.inf file from the given jar. If the file is not a jar, null is returned.
+ * If the file is a jar, but does not contain an eclipse.inf file, an empty Properties object is returned.
+ * @param jarFile
+ * @return The eclipse.inf properties for the given jar file
+ */
+ public static Properties getEclipseInf(File jarFile, boolean verbose) {
+ if (jarFile == null || !jarFile.exists()) {
+ if (verbose)
+ System.out.println("Failed to obtain eclipse.inf due to missing jar file: " + jarFile);
+ return null;
+ }
+ JarFile jar = null;
+ try {
+ jar = new JarFile(jarFile, false);
+ } catch (ZipException e) {
+ //not a jar, don't bother logging this.
+ return null;
+ } catch (IOException e) {
+ if (verbose) {
+ System.out.println("Failed to obtain eclipse.inf due to IOException: " + jarFile);
+ e.printStackTrace();
+ }
+ return null;
+ }
+ try {
+ JarEntry mark = jar.getJarEntry(MARK_FILE_NAME);
+ if (mark != null) {
+ InputStream in = jar.getInputStream(mark);
+ Properties props = new Properties();
+ props.load(in);
+ in.close();
+ return props;
+ }
+ return new Properties();
+ } catch (IOException e) {
+ if (verbose) {
+ System.out.println("Failed to obtain eclipse.inf due to IOException: " + jarFile);
+ e.printStackTrace();
+ }
+ return null;
+ } finally {
+ close(jar);
+ }
+ }
+
+ public static boolean shouldSkipJar(File input, boolean processAll, boolean verbose) {
+ Properties inf = getEclipseInf(input, verbose);
+ if (inf == null) {
+ //not a jar, could be a pack.gz
+ return false;
+ }
+ String exclude = inf.getProperty(MARK_EXCLUDE);
+
+ //was marked as exclude, we should skip
+ if (exclude != null && Boolean.valueOf(exclude).booleanValue())
+ return true;
+
+ //process all was set, don't skip
+ if (processAll)
+ return false;
+
+ //otherwise, we skip if not marked marked
+ String marked = inf.getProperty(MARK_PROPERTY);
+ return !Boolean.valueOf(marked).booleanValue();
+ }
+
+ /**
+ * Stores the given properties in the output stream. We store the properties
+ * in sorted order so that the signing hash doesn't change if the properties didn't change.
+ * @param props
+ * @param stream
+ */
+ public static void storeProperties(Properties props, OutputStream stream) {
+ PrintStream printStream = new PrintStream(stream);
+ printStream.print("#Processed using Jarprocessor\n"); //$NON-NLS-1$
+ SortedMap sorted = new TreeMap(props);
+ for (Iterator iter = sorted.keySet().iterator(); iter.hasNext();) {
+ String key = (String) iter.next();
+ printStream.print(key);
+ printStream.print(" = "); //$NON-NLS-1$
+ printStream.print(sorted.get(key));
+ printStream.print("\n");
+
+ }
+ printStream.flush();
+ }
+}
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/ZipProcessor.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/ZipProcessor.java
new file mode 100644
index 0000000..118b667
--- /dev/null
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/ZipProcessor.java
@@ -0,0 +1,243 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.jarprocessor;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+/**
+ * @author aniefer@ca.ibm.com
+ *
+ */
+public class ZipProcessor {
+
+ private IProcessStep signStep = null;
+ private IProcessStep packStep = null;
+ private IProcessStep packUnpackStep = null;
+ private IProcessStep unpackStep = null;
+
+ private String workingDirectory = null;
+ private Properties properties = null;
+ private Set packExclusions = null;
+ private Set signExclusions = null;
+ private String command = null;
+ private boolean packing = false;
+ private boolean signing = false;
+ private boolean repacking = false;
+ private boolean unpacking = false;
+ private boolean verbose = false;
+ private boolean processAll = false;
+
+ public void setWorkingDirectory(String dir) {
+ workingDirectory = dir;
+ }
+
+ public String getWorkingDirectory() {
+ if (workingDirectory == null)
+ workingDirectory = "."; //$NON-NLS-1$
+ return workingDirectory;
+ }
+
+ public void setSignCommand(String command) {
+ this.command = command;
+ this.signing = (command != null);
+ }
+
+ public void setPack(boolean pack) {
+ this.packing = pack;
+ }
+
+ public void setRepack(boolean repack) {
+ this.repacking = repack;
+ }
+
+ public void setUnpack(boolean unpack) {
+ this.unpacking = unpack;
+ }
+
+ public void setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ public void setProcessAll(boolean all) {
+ this.processAll = all;
+ }
+
+ public void processZip(File zipFile) throws ZipException, IOException {
+ if (verbose)
+ System.out.println("Processing " + zipFile.getPath()); //$NON-NLS-1$
+ ZipFile zip = new ZipFile(zipFile);
+ initialize(zip);
+
+ String extension = unpacking ? "pack.gz" : ".jar"; //$NON-NLS-1$ //$NON-NLS-2$
+ File tempDir = new File(getWorkingDirectory(), "temp_" + zipFile.getName()); //$NON-NLS-1$
+ JarProcessor processor = new JarProcessor();
+ processor.setVerbose(verbose);
+ processor.setProcessAll(processAll);
+ processor.setWorkingDirectory(tempDir.getCanonicalPath());
+ if (unpacking) {
+ processor.addProcessStep(unpackStep);
+ }
+
+ File outputFile = new File(getWorkingDirectory(), zipFile.getName() + ".temp"); //$NON-NLS-1$
+ File parent = outputFile.getParentFile();
+ if (!parent.exists())
+ parent.mkdirs();
+ ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(outputFile));
+ Enumeration entries = zip.entries();
+ if (entries.hasMoreElements()) {
+ for (ZipEntry entry = (ZipEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (ZipEntry) entries.nextElement() : null) {
+ String name = entry.getName();
+
+ InputStream entryStream = zip.getInputStream(entry);
+
+ boolean pack = packing && !packExclusions.contains(name);
+ boolean sign = signing && !signExclusions.contains(name);
+ boolean repack = repacking && !packExclusions.contains(name);
+
+ File extractedFile = null;
+
+ if (entry.getName().endsWith(extension) && (pack || sign || repack || unpacking)) {
+ extractedFile = new File(tempDir, name);
+ parent = extractedFile.getParentFile();
+ if (!parent.exists())
+ parent.mkdirs();
+ if (verbose)
+ System.out.println("Extracting " + entry.getName()); //$NON-NLS-1$
+ FileOutputStream extracted = new FileOutputStream(extractedFile);
+ Utils.transferStreams(entryStream, extracted, true); // this will close the stream
+ entryStream = null;
+
+ boolean skip = Utils.shouldSkipJar(extractedFile, processAll, verbose);
+ if (skip) {
+ //skipping this file
+ entryStream = new FileInputStream(extractedFile);
+ if (verbose)
+ System.out.println(entry.getName() + " is not marked, skipping."); //$NON-NLS-1$
+ } else {
+ if (unpacking) {
+ File result = processor.processJar(extractedFile);
+ name = name.substring(0, name.length() - extractedFile.getName().length()) + result.getName();
+ extractedFile = result;
+ } else {
+ if (repack || sign) {
+ processor.clearProcessSteps();
+ if (repack)
+ processor.addProcessStep(packUnpackStep);
+ if (sign)
+ processor.addProcessStep(signStep);
+ extractedFile = processor.processJar(extractedFile);
+ }
+ if (pack) {
+ processor.clearProcessSteps();
+ processor.addProcessStep(packStep);
+ File modifiedFile = processor.processJar(extractedFile);
+ if (modifiedFile.exists()) {
+ try {
+ String newName = name.substring(0, name.length() - extractedFile.getName().length()) + modifiedFile.getName();
+ if (verbose) {
+ System.out.println("Adding " + newName + " to " + outputFile.getPath()); //$NON-NLS-1$ //$NON-NLS-2$
+ System.out.println();
+ }
+ ZipEntry zipEntry = new ZipEntry(newName);
+ entryStream = new FileInputStream(modifiedFile);
+ zipOut.putNextEntry(zipEntry);
+ Utils.transferStreams(entryStream, zipOut, false); //we want to keep zipOut open
+ entryStream.close();
+ Utils.clear(modifiedFile);
+ } catch (IOException e) {
+ Utils.close(entryStream);
+ if (verbose) {
+ e.printStackTrace();
+ System.out.println("Warning: Problem reading " + modifiedFile.getPath() + ".");
+ }
+ }
+ entryStream = null;
+ } else if (verbose) {
+ System.out.println("Warning: " + modifiedFile.getPath() + " not found.");
+ }
+ }
+ }
+ if (extractedFile.exists()) {
+ try {
+ entryStream = new FileInputStream(extractedFile);
+ } catch (IOException e) {
+ if (verbose) {
+ e.printStackTrace();
+ System.out.println("Warning: Problem reading " + extractedFile.getPath() + ".");
+ }
+ }
+ }
+
+ if (verbose && entryStream != null) {
+ System.out.println("Adding " + name + " to " + outputFile.getPath()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ }
+ if (entryStream != null) {
+ ZipEntry newEntry = new ZipEntry(name);
+ try {
+ zipOut.putNextEntry(newEntry);
+ Utils.transferStreams(entryStream, zipOut, false);
+ zipOut.closeEntry();
+ } catch (ZipException e) {
+ if(verbose) {
+ System.out.println("Warning: " + name + " already exists in " + outputFile.getName() + ". Skipping.");
+ }
+ }
+ entryStream.close();
+ }
+
+ if (extractedFile != null)
+ Utils.clear(extractedFile);
+
+ if (verbose) {
+ System.out.println();
+ System.out.println("Processing " + zipFile.getPath()); //$NON-NLS-1$
+ }
+ }
+ }
+ zipOut.close();
+ zip.close();
+
+ File finalFile = new File(getWorkingDirectory(), zipFile.getName());
+ if (finalFile.exists())
+ finalFile.delete();
+ outputFile.renameTo(finalFile);
+ Utils.clear(tempDir);
+ }
+
+ private void initialize(ZipFile zip) {
+ ZipEntry entry = zip.getEntry("pack.properties"); //$NON-NLS-1$
+ properties = new Properties();
+ if (entry != null) {
+ InputStream stream = null;
+ try {
+ stream = zip.getInputStream(entry);
+ properties.load(stream);
+ } catch (IOException e) {
+ if (verbose)
+ e.printStackTrace();
+ } finally {
+ Utils.close(stream);
+ }
+ }
+
+ packExclusions = Utils.getPackExclusions(properties);
+ signExclusions = Utils.getSignExclusions(properties);
+
+ packUnpackStep = new PackUnpackStep(properties, verbose);
+ packStep = new PackStep(properties, verbose);
+ signStep = new SignCommandStep(properties, command, verbose);
+ unpackStep = new UnpackStep(properties, verbose);
+ }
+}
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/pack-readme.html b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/pack-readme.html
new file mode 100644
index 0000000..ef5fe5e
--- /dev/null
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/pack-readme.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <title>Eclipse update packing tool readme</title>
+</head>
+<body>
+<h1>Eclipse update packing tool</h1>
+
+<h3>Overview</h3>
+The update packing tool processes a hierarchy of arbitrarily nested
+JARs and ZIP files. It is a generic utility that performs a depth first traversal of
+a nested hierarchy of ZIPs and JARs, performs various commands on
+each of the JARs in the hierarchy, and then rebuilds the same hierarchy
+of ZIPs and JARs again. Currently its main functions are:
+<ul>
+ <li>Packing JARs using the Java 1.5 <a href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/pack200.html">pack200</a>
+ command.</li>
+ <li>Unpacking PACK.GZs using the Java 1.5 <a href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/unpack200.html">unpack200</a>
+ command.</li>
+ <li>Normalizing JARs for future compression by pack200. This is accomplished
+ by running the pack200 command with the <tt>--repack</tt> command line argument.</li>
+ <li>Signing JARs to allow for authentication of the origin of JARs. This is accomplished by
+ running a supplied command (typically the command will just be a wrapper around
+ the Java <a href="http://java.sun.com/j2se/1.3/docs/tooldocs/win32/jarsigner.html">jarsigner</a> tool).</li>
+</ul>
+The packing tool is used in the following contexts:
+<ul>
+ <li>During a PDE build, to prepare JARs for uploading to an Eclipse
+ update site. In this usage, it is used to both nomalize JAR contents
+ (pack200 -repack), and sign JARs.</li>
+ <li>On an update site, to convert traditional JAR content into the
+ compressed pack200 format.</li>
+ <li>From an Eclipse client application during update, to convert
+ compressed pack200 format content into executable JAR files.</li>
+</ul>
+<h3>Tool usage</h3>
+To run the packing tool, you need a 1.5 JRE installed. The tool is run
+by invoking Java as follows:
+
+<pre>
+ java jarprocessor.jar [options] input
+</pre>
+
+Where <tt>input</tt> is either a zip file, a directory, or a JAR (or a pack.gz file). All files ending
+in ".jar" or ".pack.gz" in the provided zip or directory hierarchy
+will be processed.
+The following additional command line arguments are supported:
+<ul>
+<li>-repack : Normalize the jars using pack200 <tt>--repack</tt></li>
+<li>-sign <cmd> : signs the jars by executing the provided command.
+The command will be provided a single argument that will be the full path of the JAR to process.
+</li>
+<li>-pack : for each input in JAR form, produce a corresponding output
+in packed form. For an input "a.jar", the output is a.jar.pack.gz.
+</li>
+<li>-unpack : for each input in packed form, produce a corresponding output
+in unpacked form. For an input "a.jar.pack.gz", the output is "a.jar". -unpack is mutually exclusive with -repack, -pack and -sign.</li>
+<li>-outputDir <dir> : The directory to put the tool's output into. If the input was a zip file, then an output zip file will be
+created containg all the output files. If the input was a directory, for each input file there is a corresponding output file in the output directory. By default the current working directory is used. If the input is in the same
+directory as the output, the input files may be overwritten.</li>
+</ul>
+
+Additionally, when the input is a zip file, it may contain a file called
+<tt>pack.properties</tt>. The pack.properties file supports the following values:
+<ul>
+<li>pack.excludes = jarName[, jarName]* : A comma-delimited list of JARs that should not be packed or repacked.
+</li>
+<li>sign.excludes = jarName[, jarName]* : A comma-delimited list of JARs that should not be signed.
+</li>
+<li><jarname>.pack.args = option[, option]* : A comma-delimited list of additional arguments that should
+be passed to pack200 when packing any jar with name <jarname>.
+</ul>
+</p>
+<p>
+<font size=-1>
+Copyright (c) IBM Corporation and others 2006. All rights reserved. This program and the accompanying materials
+are made available under the terms of the
+<a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License v1.0</a>.
+</font>
+</body>
+</html>
diff --git a/update/org.eclipse.update.core/plugin.properties b/update/org.eclipse.update.core/plugin.properties
new file mode 100644
index 0000000..baa2ab4
--- /dev/null
+++ b/update/org.eclipse.update.core/plugin.properties
@@ -0,0 +1,20 @@
+###############################################################################
+# Copyright (c) 2000, 2011 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
+###############################################################################
+pluginName= Install/Update Core
+providerName= Eclipse.org
+fragmentNameWin= Install/Update Core for Windows
+fragmentNameLinux= Install/Update Core for Linux
+featureTypes.name=Install/Update Concrete Feature Type Implementation Factory
+siteTypes.name=Install/Update Concrete Site Type Implementation Factory
+installHandlers.name=Install/Update Global Install Handlers
+deltaHandler.name=Install/Update Delta Handler
+productProviderName= Update Core Product Provider
+
diff --git a/update/org.eclipse.update.core/plugin.xml b/update/org.eclipse.update.core/plugin.xml
new file mode 100644
index 0000000..db0d7fd
--- /dev/null
+++ b/update/org.eclipse.update.core/plugin.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<!--
+ Copyright (c) 2005, 2010 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Public License v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/legal/epl-v10.html
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+ -->
+
+<plugin>
+
+ <extension-point id="featureTypes" name="%featureTypes.name" schema="schema/featureTypes.exsd"/>
+ <extension-point id="siteTypes" name="%siteTypes.name" schema="schema/siteTypes.exsd"/>
+ <extension-point id="installHandlers" name="%installHandlers.name" schema="schema/installHandlers.exsd"/>
+ <!-- The deltaHandler extension point is deprecated. Do not use it -->
+ <extension-point id="deltaHandler" name="%deltaHandler.name"/>
+
+ <extension
+ id="preferenceInitializer"
+ point="org.eclipse.core.runtime.preferences">
+ <initializer class="org.eclipse.update.internal.core.UpdatePreferencesInitializer"/>
+ </extension>
+
+ <extension
+ id="packaged"
+ point="org.eclipse.update.core.featureTypes">
+ <feature-factory
+ class="org.eclipse.update.internal.core.FeaturePackagedFactory">
+ </feature-factory>
+ </extension>
+ <extension
+ id="installed"
+ point="org.eclipse.update.core.featureTypes">
+ <feature-factory
+ class="org.eclipse.update.internal.core.FeatureExecutableFactory">
+ </feature-factory>
+ </extension>
+ <extension
+ id="http"
+ point="org.eclipse.update.core.siteTypes">
+ <site-factory
+ class="org.eclipse.update.internal.core.ExtendedSiteURLFactory">
+ </site-factory>
+ </extension>
+ <extension
+ id="file"
+ point="org.eclipse.update.core.siteTypes">
+ <site-factory
+ class="org.eclipse.update.internal.core.SiteFileFactory">
+ </site-factory>
+ </extension>
+ <extension
+ id="DefaultInstallHandler"
+ point="org.eclipse.update.core.installHandlers">
+ <install-handler
+ class="org.eclipse.update.internal.core.DefaultInstallHandler">
+ </install-handler>
+ </extension>
+ <extension
+ id="DeltaInstallHandler"
+ point="org.eclipse.update.core.installHandlers">
+ <install-handler
+ class="org.eclipse.update.internal.core.DeltaInstallHandler">
+ </install-handler>
+ </extension>
+ <extension
+ id="JarDeltaInstallHandler"
+ point="org.eclipse.update.core.installHandlers">
+ <install-handler
+ class="org.eclipse.update.internal.core.JarDeltaInstallHandler">
+ </install-handler>
+ </extension>
+ <extension
+ id="standaloneUpdate"
+ point="org.eclipse.core.runtime.applications">
+ <application>
+ <run
+ class="org.eclipse.update.standalone.StandaloneUpdateApplication">
+ </run>
+ </application>
+ </extension>
+ <extension
+ id="siteOptimizer"
+ point="org.eclipse.core.runtime.applications">
+ <application>
+ <run
+ class="org.eclipse.update.internal.provisional.SiteOptimizerApplication">
+ </run>
+ </application>
+ </extension>
+ <extension
+ id="updateCoreProductProvider"
+ name="%productProviderName"
+ point="org.eclipse.core.runtime.products">
+ <provider>
+ <run class="org.eclipse.update.internal.core.ProductProvider"/>
+ </provider>
+ </extension>
+
+</plugin>
diff --git a/update/org.eclipse.update.core/pom.xml b/update/org.eclipse.update.core/pom.xml
new file mode 100644
index 0000000..dd8679e
--- /dev/null
+++ b/update/org.eclipse.update.core/pom.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2012 Eclipse Foundation.
+ All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Distribution License v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/org/documents/edl-v10.php
+
+ Contributors:
+ Igor Fedorenko - initial implementation
+-->
+
+<project
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>eclipse.platform</artifactId>
+ <groupId>org.eclipse.platform</groupId>
+ <version>3.8.0-SNAPSHOT</version>
+ <relativePath>../../</relativePath>
+ </parent>
+ <groupId>org.eclipse.platform</groupId>
+ <artifactId>org.eclipse.update.core</artifactId>
+ <version>3.2.600-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+</project>
diff --git a/update/org.eclipse.update.core/preferences.ini b/update/org.eclipse.update.core/preferences.ini
new file mode 100644
index 0000000..7936e7f
--- /dev/null
+++ b/update/org.eclipse.update.core/preferences.ini
@@ -0,0 +1,8 @@
+# The port number on which the sever listens for http requests.
+# If the port is 0 and arbitrary port is picked by the system.
+
+# Defines the policy url that contains directives for redirecting
+# updates to different update sites.
+#updatePolicyURL=
+
+
diff --git a/update/org.eclipse.update.core/schema/featureTypes.exsd b/update/org.eclipse.update.core/schema/featureTypes.exsd
new file mode 100644
index 0000000..0517f10
--- /dev/null
+++ b/update/org.eclipse.update.core/schema/featureTypes.exsd
@@ -0,0 +1,122 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.update.core">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="org.eclipse.update.core" id="featureTypes" name="Feature Type Factory"/>
+ </appInfo>
+ <documentation>
+ The platform update mechanism supports pluggable feature type
+implementations. A new feature type can be registered in order
+to support
+alternate packaging and verification schemes.
+<p>
+The <code>featureTypes</code>
+extension point allows alternate feature implementations to be
+registered using a symbolic type identifier. Whenever the
+type is referenced using this identifier, the supplied factory
+is used to create the correct concrete feature implementation.
+</p>
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <complexType>
+ <sequence>
+ <element ref="feature-factory" minOccurs="1" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+ must be specified as <b>org.eclipse.update.core.featureTypes</b>
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+ must be specified. Identifies the new feature type
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+ optional displayable label for the new feature type
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="feature-factory">
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ fully qualified name of the factory class for the identified feature type
+ </documentation>
+ <appInfo>
+ <meta.attribute kind="java" basedOn="org.eclipse.update.configuration.IInstallDeltaHandler"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="examples"/>
+ </appInfo>
+ <documentation>
+ The following is an example of new feature type registration:
+<p>
+<pre>
+ <extension
+ id="custom"
+ point="org.eclipse.update.core.featureTypes"
+ name="Custom packaged feature">
+ <feature-factory
+ class="com.xyz.update.CustomFeatureFactory">
+ </feature-factory>
+ </extension>
+</pre>
+</p>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiInfo"/>
+ </appInfo>
+ <documentation>
+ Registered factory classes must implement
+<code><b>org.eclipse.update.core.IFeatureFactory</b></code>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="implementation"/>
+ </appInfo>
+ <documentation>
+ The platform supplies two standard implementations of feature
+types. One representing the default packaged feature type, and
+the other representing an installed feature type.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="copyright"/>
+ </appInfo>
+ <documentation>
+ Copyright (c) 2004 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 <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/update/org.eclipse.update.core/schema/installHandlers.exsd b/update/org.eclipse.update.core/schema/installHandlers.exsd
new file mode 100644
index 0000000..084a25f
--- /dev/null
+++ b/update/org.eclipse.update.core/schema/installHandlers.exsd
@@ -0,0 +1,113 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.update.core">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="org.eclipse.update.core" id="installHandlers" name="Global Install Handlers"/>
+ </appInfo>
+ <documentation>
+ Extension point for registering global install handlers. Global
+install handlers can be referenced by features
+(using the <code>&lt;feature&gt; &lt;install-handler&gt;</code>
+tags) without having to include a copy of the handler code as
+part of the downloadable feature.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <complexType>
+ <sequence>
+ <element ref="install-handler" minOccurs="1" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+ must be specified as <b>org.eclipse.update.core.installHandlers</b>
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+ must be specified. Identifies the new install handler
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+ optional displayable label for the new install handler
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="install-handler">
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ fully qualified name of the handler implementation class for the identified
+install handler
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="examples"/>
+ </appInfo>
+ <documentation>
+ The following is an example of new global install handler registration:
+<p>
+<pre>
+ <extension
+ id="custom"
+ point="org.eclipse.update.core.installHandlers"
+ name="Custom install handler">
+ <install-handler
+ class="com.xyz.update.CustomInstallHandler">
+ </install-handler>
+ </extension>
+</pre>
+</p>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiInfo"/>
+ </appInfo>
+ <documentation>
+ Registered install handler classes must implement
+<code>org.eclipse.update.core.IInstallHandler</code> interface.
+Implementers should extend base class <code>org.eclipse.update.core.BaseInstallHandler</code>.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="implementation"/>
+ </appInfo>
+ <documentation>
+ The platform supplies a simple install handler that is registered as <code>org.eclipse.update.core.DefaultInstallHandler</code>. If used, it will copy any non-plug-in data entries provided with the feature into the feature installation directory.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="copyright"/>
+ </appInfo>
+ <documentation>
+ Copyright (c) 2004 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 <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/update/org.eclipse.update.core/schema/siteTypes.exsd b/update/org.eclipse.update.core/schema/siteTypes.exsd
new file mode 100644
index 0000000..102dc16
--- /dev/null
+++ b/update/org.eclipse.update.core/schema/siteTypes.exsd
@@ -0,0 +1,119 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.update.core">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="org.eclipse.update.core" id="siteTypes" name="Site Type Factory"/>
+ </appInfo>
+ <documentation>
+ The platform update mechanism supports pluggable site type
+implementations. A new site type can be registered in order
+to support alternate site layout schemes.
+<p>
+The <code>siteTypes</code>
+extension point allows alternate site implementations to be
+registered using a symbolic type identifier. Whenever the
+type is referenced using this identifier, the supplied factory
+is used to create the correct concrete site implementation.
+</p>
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <complexType>
+ <sequence>
+ <element ref="site-factory" minOccurs="1" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+ must be specified as <b>org.eclipse.update.core.siteTypes</b>
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+ must be specified. Identifies the new site type
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+ optional displayable label for the new site type
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="site-factory">
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ fully qualified name of the factory class for the identified
+site type
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="examples"/>
+ </appInfo>
+ <documentation>
+ The following is an example of new site type registration.
+<p>
+<pre>
+ <extension
+ id="custom"
+ point="org.eclipse.update.core.siteTypes"
+ name="Custom site">
+ <site-factory
+ class="com.xyz.update.CustomSiteFactory">
+ </site-factory>
+ </extension>
+</pre>
+</p>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiInfo"/>
+ </appInfo>
+ <documentation>
+ Registered factory classes must implement
+<code><b>org.eclipse.update.core.ISiteFactory</b></code>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="implementation"/>
+ </appInfo>
+ <documentation>
+ The platform supplies two standard implementations of site
+types. One representing the default update server type, and
+the other representing the local file system site.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="copyright"/>
+ </appInfo>
+ <documentation>
+ Copyright (c) 2004 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 <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IActivity.java b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IActivity.java
new file mode 100644
index 0000000..6c18192
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IActivity.java
@@ -0,0 +1,261 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.configuration;
+
+import java.util.Date;
+
+import org.eclipse.core.runtime.*;
+
+/**
+ * Install activity.
+ * Represents a record of an installation action performed
+ * on a particular installation configuration.
+ * <p>
+ * This interface is not intended to 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>
+ * @see org.eclipse.update.configuration.IInstallConfiguration
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IActivity extends IAdaptable {
+
+ /**
+ * Indicates feature installation action
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int ACTION_FEATURE_INSTALL = 1;
+
+ /**
+ * Indicates feature removal (uninstallation) action
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int ACTION_FEATURE_REMOVE = 2;
+
+ /**
+ * Indicates an addition of a site to a configuration
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int ACTION_SITE_INSTALL = 3;
+
+ /**
+ * Indicates removal of a site from a configuration
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int ACTION_SITE_REMOVE = 4;
+
+ /**
+ * Indicates feature unconfiguration action
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int ACTION_UNCONFIGURE = 5;
+
+ /**
+ * Indicates feature configuration action
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int ACTION_CONFIGURE = 6;
+
+ /**
+ * Indicates reverting to a prior configuration state
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int ACTION_REVERT = 7;
+
+ /**
+ * Indicates reconcilliation with changes made directly to the site
+ * installation directory
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int ACTION_RECONCILIATION = 8;
+
+ /**
+ * Indicates adding the configuration to a preserved state
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int ACTION_ADD_PRESERVED = 9;
+
+ /**
+ * Indicates the action completed cussessfully
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int STATUS_OK = 0;
+
+ /**
+ * Indicates the action did not complete successfully
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int STATUS_NOK = 1;
+
+ /**
+ * Returns the action code for this activity
+ *
+ * @see #ACTION_FEATURE_INSTALL
+ * @see #ACTION_FEATURE_REMOVE
+ * @see #ACTION_SITE_INSTALL
+ * @see #ACTION_SITE_REMOVE
+ * @see #ACTION_UNCONFIGURE
+ * @see #ACTION_CONFIGURE
+ * @see #ACTION_REVERT
+ * @see #ACTION_RECONCILIATION
+ * @return action code, as defined in this interface
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 int getAction();
+
+ /**
+ * Returns the displayable label for this action
+ *
+ * @return diplayable label for action
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 String getLabel();
+
+ /**
+ * Returns the creation date of this activity
+ *
+ * @return activity date
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 Date getDate();
+
+ /**
+ * Returns the activity completion status
+ *
+ * @see #STATUS_OK
+ * @see #STATUS_NOK
+ * @return completion status, as defined in this interface
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 int getStatus();
+
+ /**
+ * Returns the installation configuration that was the result of
+ * this action
+ *
+ * @return installation configuration
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IInstallConfiguration getInstallConfiguration();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IConfiguredSite.java b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IConfiguredSite.java
new file mode 100644
index 0000000..8c5aaf8
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IConfiguredSite.java
@@ -0,0 +1,380 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.configuration;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IFeatureReference;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.IVerificationListener;
+
+/**
+ * Configured Site.
+ * Represents an installation site "filtered" by configuration information.
+ * Configured site is the target of the feature update operations (install
+ * feature, remove feature, configure feature, unconfigure feature).
+ * <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>
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IConfiguredSite extends IAdaptable {
+
+ /**
+ * Returns the underlying "unfiltered" site.
+ *
+ * @return the underlying site
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 ISite getSite();
+
+ /**
+ * Indicates whether updates can be applied to the site.
+ *
+ * <code>IStatus.isOk()</code> return <code>true</code> if
+ * the site can be updated, <code>false</code> otherwise.
+ *
+ * If updates cannot be aplied, the status contains the error message, and
+ * the possible exception.
+ *
+ * @see IStatus
+ * @return an IStatus
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IStatus verifyUpdatableStatus();
+
+ /**
+ * Indicates whether updates can be applied to the site.
+ *
+ * A configuration site is tagged a non-updatable by reading
+ * the platform configuration for this site.
+ *
+ * @return <code>true</code> if the site can be updated,
+ * <code>false</code> otherwise
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 boolean isUpdatable();
+
+ /**
+ * Install the specified feature on this site.
+ *
+ * @param feature feature to install
+ * @param verificationListener verification listener, or <code>null</code>
+ * @param monitor progress monitor, or <code>null</code>
+ * @exception CoreException
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IFeatureReference install(IFeature feature, IVerificationListener verificationListener, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Install the specified feature on this site.
+ * Only the specified optional features will be installed
+ *
+ * @param feature feature to install
+ * @param optionalFeatures optional features to install
+ * @param verificationListener verification listener, or <code>null</code>
+ * @param monitor progress monitor, or <code>null</code>
+ * @exception CoreException
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IFeatureReference install(IFeature feature, IFeatureReference[] optionalFeatures, IVerificationListener verificationListener, IProgressMonitor monitor) throws CoreException;
+
+
+ /**
+ * Remove (uninstall) the specified feature from this site
+ *
+ * @param feature feature to remove
+ * @param monitor progress monitor, or <code>null</code>
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void remove(IFeature feature, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Indicates if the specified feature is "broken". A feature is considered
+ * to be broken in the context of this site, if some of the plug-ins
+ * referenced by the feature are not installed on this site.
+ *
+ * The status code is <code>IStatus.ERROR</code> if the feature is considered
+ * broken. The Status may contain the reason why the feature is broken.
+ * The status code is <code>IStatus.OK</code> if the feature is not considered
+ * broken.
+ *
+ * @param feature the feature
+ * @return the status for this feature on this configured site
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IStatus getBrokenStatus(IFeature feature);
+
+ /**
+ * Indicates if the specified feature is configured on this site.
+ *
+ * @param feature the feature
+ * @return <code>true</code> if the feature is configured,
+ * <code>false</code> otherwise
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 boolean isConfigured(IFeature feature);
+
+ /**
+ * Configure the specified feature on this site. The configured
+ * feature will be included on next startup.
+ *
+ * @param feature the feature
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void configure(IFeature feature) throws CoreException;
+
+ /**
+ * Unconfigure the specified feature from this site. The unconfigured
+ * feature will be omitted on the next startup.
+ *
+ * @param feature the feature
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 boolean unconfigure(IFeature feature) throws CoreException;
+
+ /**
+ * Return references to features configured on this site.
+ *
+ * @return an array of feature references, or an empty array.
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IFeatureReference[] getConfiguredFeatures();
+
+ /**
+ * Return all features installed on this site (configured as well
+ * as unconfigured). Note, that if the site requires reconciliation,
+ * the result may not match the result of the corresponding method
+ * on the underlying site.
+ *
+ * @see ISite#getFeatureReferences()
+ * @return an array of site feature references, or an empty array.
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IFeatureReference[] getFeatureReferences();
+
+ /**
+ * Returns the install configuration object this site is part of.
+ *
+ * @return install configuration object
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IInstallConfiguration getInstallConfiguration();
+
+ /**
+ * Adds a change listener to the configured site.
+ *
+ * @param listener the listener to add
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void addConfiguredSiteChangedListener(IConfiguredSiteChangedListener listener);
+
+ /**
+ * Removes a change listener from the configured site.
+ *
+ * @param listener the listener to remove
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void removeConfiguredSiteChangedListener(IConfiguredSiteChangedListener listener);
+
+ /**
+ * Indicates if the site is an extension site.
+ *
+ * @return <code>true</code> if the site is an extension site,
+ * <code>false</code> otherwise
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 boolean isExtensionSite();
+
+ /**
+ * Indicates if the site is a product site.
+ *
+ * @return <code>true</code> if the site is a product site,
+ * <code>false</code> otherwise
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 boolean isProductSite();
+
+ /**
+ * Indicates if the site is a private site.
+ * This does not check if this private site belongs to the
+ * product that is running.
+ *
+ * @return <code>true</code> if the site is a private site,
+ * <code>false</code> otherwise
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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>
+ * @deprecated private site are considered the same as extension site (3.0)
+ */
+ public boolean isPrivateSite();
+
+ /**
+ * Indicates if the site has been linked by a native
+ * installer.
+ *
+ * @return <code>true</code> if the site is a natively linked site,
+ * <code>false</code> otherwise
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 boolean isNativelyLinked() throws CoreException;
+
+ /**
+ * Sets if the site is enabled
+ *
+ * @param value <code>true</code> if the site is enable, <code>false</code>
+ * otherwise
+ * @since 2.1
+ * <p>
+ * <b>Note:</b> This method 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 void setEnabled(boolean value);
+
+ /**
+ * Indicates if the site is enabled.
+ * If a site is not enable, all teh features are considered disabled.
+ *
+ * @return <code>true</code> if the site is enable, <code>false</code>
+ * otherwise
+ * @since 2.1
+ * <p>
+ * <b>Note:</b> This method 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 boolean isEnabled();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IConfiguredSiteChangedListener.java b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IConfiguredSiteChangedListener.java
new file mode 100644
index 0000000..7266208
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IConfiguredSiteChangedListener.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.configuration;
+
+import org.eclipse.update.core.IFeature;
+
+/**
+ * Configuration change listener. *
+ * <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>
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IConfiguredSiteChangedListener {
+
+ /**
+ * Indicates the specified feature was installed.
+ *
+ * @param feature the feature
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void featureInstalled(IFeature feature);
+
+ /**
+ * Indicates the specified feature was removed (uninstalled)
+ *
+ * @param feature the feature
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void featureRemoved(IFeature feature);
+
+ /**
+ * Indicates the specified feature was configured.
+ *
+ * @param feature the feature
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void featureConfigured(IFeature feature);
+
+ /**
+ * Indicates the specified feature was unconfigured.
+ *
+ * @param feature the feature
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void featureUnconfigured(IFeature feature);
+}
+
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IInstallConfiguration.java b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IInstallConfiguration.java
new file mode 100644
index 0000000..473b970
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IInstallConfiguration.java
@@ -0,0 +1,237 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.configuration;
+
+import java.io.File;
+import java.util.Date;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * Installation configuration.
+ * Represents a specific configuration of a number of sites as a point
+ * in time. Maintains a record of the specific activities that resulted
+ * in this configuration. Current installation configuration is
+ * the configuration the platform was started with.
+ * <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>
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IInstallConfiguration extends IAdaptable {
+
+ /**
+ * Indicates if this is the current configuration
+ *
+ * @return <code>true</code> if this is the current configuration,
+ * <code>false</code> otherwise
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 boolean isCurrent();
+
+ /**
+ * Return the sites that are part of this configuration.
+ *
+ * @return an array of configured sites, or an empty array.
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IConfiguredSite[] getConfiguredSites();
+
+ /**
+ * Create a new installation site, based on a local file
+ * system directory. Note, the site is not added to the
+ * configuration as a result of this call.
+ *
+ * @param directory file directory
+ * @return new site
+ * @exception CoreException
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IConfiguredSite createConfiguredSite(File directory) throws CoreException;
+
+ /**
+ * Create a new linked site, based on a local file
+ * system directory. Note, the site is not added to the
+ * configuration as a result of this call.
+ * The linked site is only created if the directory is an
+ * already existing extension site and if it is not already
+ * natively linked to the local site.
+ *
+ * @param directory file directory
+ * @return new linked site
+ * @exception CoreException
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IConfiguredSite createLinkedConfiguredSite(File directory) throws CoreException;
+
+ /**
+ * Adds the specified site to this configuration.
+ *
+ * @param site new site
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void addConfiguredSite(IConfiguredSite site);
+
+ /**
+ * Removes the specified site from this configuration.
+ *
+ * @param site site to remove
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void removeConfiguredSite(IConfiguredSite site);
+
+ /**
+ * Adds a configuration change listener.
+ *
+ * @param listener the listener
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void addInstallConfigurationChangedListener(IInstallConfigurationChangedListener listener);
+
+ /**
+ * Removes a configuration change listener.
+ *
+ * @param listener the listener
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void removeInstallConfigurationChangedListener(IInstallConfigurationChangedListener listener);
+
+ /**
+ * Return the list of activities that resulted in this configuration.
+ * There is always at least one activity
+ *
+ * @return an array of activities
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IActivity[] getActivities();
+
+ /**
+ * Retrun the date the configuration was created.
+ *
+ * @return create date
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 Date getCreationDate();
+
+ /**
+ * Return the configuration label.
+ *
+ * @return the configuration label. If the configuration label was not
+ * explicitly set, a default label is generated based on the creation
+ * date
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 String getLabel();
+
+ /**
+ * Sets the configuration label.
+ *
+ * @param label the label
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void setLabel(String label);
+
+ /**
+ * Returns an integer that represents a time stamp created at the beginning of a new configuration time line.
+ * Time line is started when configuration state is created by a full file system reconciliation. All configurations
+ * subsequently created will have the same time line until the next full reconciliation. Certain operations
+ * (e.g. revert) make sense only between objects that belong to the same time line.
+ *
+ * @since 2.0.2
+ * @return the time stamp of the full system reconciliation
+ *
+ * <b>Note:</b> This method 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 long getTimeline();
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IInstallConfigurationChangedListener.java b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IInstallConfigurationChangedListener.java
new file mode 100644
index 0000000..d6f02c2
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IInstallConfigurationChangedListener.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.configuration;
+
+/**
+ * Configuration change listener.
+ * <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>
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IInstallConfigurationChangedListener {
+
+ /**
+ * Indicates the specified site was added to the configuration
+ *
+ * @param site the site
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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>
+ */
+ void installSiteAdded(IConfiguredSite site);
+
+ /**
+ * Indicates the specified site was removed from the configuration
+ *
+ * @param site the site
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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>
+ */
+ void installSiteRemoved(IConfiguredSite site);
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IInstallDeltaHandler.java b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IInstallDeltaHandler.java
new file mode 100644
index 0000000..71e92e2
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IInstallDeltaHandler.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.configuration;
+
+/**
+ * Install Delta Handler.
+ * Presents the changes the reconciler found to the user
+ * <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>
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IInstallDeltaHandler{
+
+ /**
+ * Sets the list of session delta to present to the user
+ *
+ * @param deltas an Array of <code>ISessionDelta</code>
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void init(ISessionDelta[] deltas);
+
+ /**
+ * Prompt the user to configure or unconfigure
+ * new features found during reconciliation
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void open();
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/ILocalSite.java b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/ILocalSite.java
new file mode 100644
index 0000000..bcc03e9
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/ILocalSite.java
@@ -0,0 +1,274 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.configuration;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.update.core.IFeature;
+
+/**
+ * Local Site.
+ * Represents the local installation. It consists of the current
+ * configuration and the configuration history. A local site
+ * manages the number of configuration histories kept. It also allows
+ * specific configuration histories to be saved.
+ * <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>
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface ILocalSite extends IAdaptable {
+
+ /**
+ * Return the current configuration.
+ *
+ * @return current configuration
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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>
+ */
+ IInstallConfiguration getCurrentConfiguration();
+
+ /**
+ * Return configuration history.
+ *
+ * @return an array of configurations, or an empty array.
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IInstallConfiguration[] getConfigurationHistory();
+
+ /**
+ * Reverts the local site to use the specified configuration.
+ * The result of this operation is a new configuration that
+ * contains the same configured features as the specified configuration.
+ * The new configuration becomes the current configuration.
+ *
+ * @param configuration configuration state to revert to
+ * @param monitor progress monitor
+ * @param handler problem handler
+ * @exception CoreException
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void revertTo(
+ IInstallConfiguration configuration,
+ IProgressMonitor monitor,
+ IProblemHandler handler)
+ throws CoreException;
+
+ /**
+ * Creates a new configuration containing the same state as the
+ * specified configuration. The new configuration is not added to
+ * this lical site.
+ *
+ * @return cloned configuration
+ * @exception CoreException
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IInstallConfiguration cloneCurrentConfiguration() throws CoreException;
+
+ /**
+ * Adds the specified configuration to this local site.
+ * The new configuration becomes the current one.
+ *
+ * @param config the configuration
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void addConfiguration(IInstallConfiguration config);
+
+ /**
+ * Saves the local site state
+ *
+ * @exception CoreException
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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>
+ * @return true if a restart is needed. This return code was added in 3.0.
+ */
+ public boolean save() throws CoreException;
+
+ /**
+ * Indicates how many configuration histories should be maintained.
+ * Histories beyond the specified count are automatically deleted.
+ *
+ * @return number of past configurations to keep as history
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 int getMaximumHistoryCount();
+
+ /**
+ * Sets the number of past configurations to keep in history
+ *
+ * @param history number of configuration to keep
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void setMaximumHistoryCount(int history);
+
+ /**
+ * Adds a site change listener
+ *
+ * @param listener the listener
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void addLocalSiteChangedListener(ILocalSiteChangedListener listener);
+
+ /**
+ * Removes a site listener
+ *
+ * @param listener the listener
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void removeLocalSiteChangedListener(ILocalSiteChangedListener listener);
+
+ /**
+ * Save the specified configuration. Saved configurations are
+ * not deleted based on the history count. They must be explicitly
+ * removed.
+ *
+ * @param configuration the configuration to save
+ * @return the preserved configuration or <code>null</code> if the configuration to save is <code>null</code>
+ * @exception CoreException
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IInstallConfiguration addToPreservedConfigurations(IInstallConfiguration configuration)
+ throws CoreException;
+
+ /**
+ * Removes the specified configuration from the list of previously
+ * saved configurations.
+ *
+ * @param configuration the configuration to remove
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void removeFromPreservedConfigurations(IInstallConfiguration configuration);
+
+ /**
+ * Return the list of saved configurations
+ *
+ * @return an array of configurations, or an empty array.
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IInstallConfiguration[] getPreservedConfigurations();
+
+ /**
+ * Indicates if the 'state' of the specified feature and its children features.
+ *
+ * A feature is considered to be 'unhappy' in the context of this site,
+ * if some of the plug-ins referenced by the feature, or any of its children,
+ * are not installed on this site.
+ *
+ * A feature is considered to be 'happy' in the context of a local site
+ * if all the plug-ins referenced by the feature, or any of its children,
+ * are installed on the site and no other version of any of the plug-ins
+ * are installed on any other site of the local site.
+ *
+ * A feature is considered to be 'ambiguous' in the context of a local site
+ * if all the plug-ins referenced by the feature, or any of its children,
+ * are installed on the site and other version of any of the plug-ins
+ * are installed on any other site of the local site.
+ *
+ * @param feature the feature
+ * @see IFeature#STATUS_HAPPY
+ * @see IFeature#STATUS_UNHAPPY
+ * @see IFeature#STATUS_AMBIGUOUS
+ * @return the state of the feature
+ * @exception CoreException
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IStatus getFeatureStatus(IFeature feature) throws CoreException ;
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/ILocalSiteChangedListener.java b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/ILocalSiteChangedListener.java
new file mode 100644
index 0000000..98cc3ea
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/ILocalSiteChangedListener.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.configuration;
+
+/**
+ * Local site change listener.
+ * <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>
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface ILocalSiteChangedListener {
+
+ /**
+ * Indicates the current configuration has changed.
+ *
+ * @param configuration the current cunfiguration
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void currentInstallConfigurationChanged(IInstallConfiguration configuration);
+
+ /**
+ * Indicates the specified configuration was removed.
+ *
+ * @param configuration the configuration
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void installConfigurationRemoved(IInstallConfiguration configuration);
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/ILocalSystemInfoListener.java b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/ILocalSystemInfoListener.java
new file mode 100644
index 0000000..a2f3987
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/ILocalSystemInfoListener.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.configuration;
+
+
+
+/**
+ * Local system change listener interface.
+ * <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>
+ * @see LocalSystemInfo#addInfoListener(ILocalSystemInfoListener)
+ * @see LocalSystemInfo#removeInfoListener(ILocalSystemInfoListener)
+ * @see LocalSystemInfo#fireSystemInfoChanged(IVolume,int)
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface ILocalSystemInfoListener {
+
+ /**
+ * Volume change notification.
+ * Called each time there are relevant volume changes
+ * detected. This specifically includes changes to the
+ * file system structure as a result of removable drive/ media
+ * operations (eg. CD insertion), and changes to volume
+ * mount structure.
+ * @param volume volume of the changed file
+ * system structure. Any current paths beyond
+ * the specified 'root' file of the volume are assumed to be invalidated.
+ * @param changeType type of the change that occured.
+ * @see LocalSystemInfo#VOLUME_ADDED
+ * @see LocalSystemInfo#VOLUME_REMOVED
+ * @see LocalSystemInfo#VOLUME_CHANGED
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void systemInfoChanged(IVolume volume, int changeType);
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IProblemHandler.java b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IProblemHandler.java
new file mode 100644
index 0000000..037d672
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IProblemHandler.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.configuration;
+
+/**
+ * Generic problem handler. Used to report status from specific
+ * install operations. The methods implemented by this interface
+ * are callbacks from the update support to the caller of the update
+ * methods.
+ * <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>
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IProblemHandler {
+
+ /**
+ * Report problem.
+ *
+ * @param problemText problem text
+ * @return <code>true</code> if the operation should continue,
+ * <code>false</code> if the operation should be cancelled
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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>
+ */
+ boolean reportProblem(String problemText);
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/ISessionDelta.java b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/ISessionDelta.java
new file mode 100644
index 0000000..1d843a5
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/ISessionDelta.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.configuration;
+
+import java.util.Date;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+
+/**
+ * Installation Change.
+ * Represents the changes the reconciler found.
+ * <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>
+ * @since 2.0
+ * @deprecated Do not use this interface
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface ISessionDelta extends IAdaptable {
+
+ /**
+ * Indicates a processing type to enable the features
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 int ENABLE = 1;
+
+ /**
+ * Indicates a processing type to disable the features
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 int DISABLE = 2;
+
+ /**
+ * Returns the list of Features found during reconciliation
+ *
+ * @return an array of feature references, or an empty array
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 IFeatureReference[] getFeatureReferences();
+
+ /**
+ * Returns the date the reconciliation occured
+ *
+ * @return the date of the reconciliation
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 Date getDate();
+
+ /**
+ * Returns the type of the processing type
+ * that will affect all the associated features.
+ *
+ * @return the processing type
+ * @see ISessionDelta#ENABLE
+ * @see ISessionDelta#DISABLE
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 int getType();
+
+ /**
+ * Process all the feature references of the
+ * Session Delta.
+ * Removes the Session Delta from the file system after processing it.
+ *
+ * @param progressMonitor the progress monitor
+ * @throws CoreException if an error occurs.
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void process(IProgressMonitor progressMonitor) throws CoreException;
+
+ /**
+ * Process the selected feature references of the Session Delta.
+ * Removes the Session Delta from the file system after processing it.
+ *
+ * @param selected list of selected feature references to be processed
+ * @param monitor the progress monitor
+ * @throws CoreException if an error occurs.
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void process(IFeatureReference [] selected, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Removes the Session Delta from the file system without processing it.
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 void delete();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IVolume.java b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IVolume.java
new file mode 100644
index 0000000..c120efc
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/IVolume.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.configuration;
+
+import java.io.File;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * Local Volume Info.
+ * Represents local file system information for a specific volume.
+ * <p>
+ * This interface is not intended to 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>
+ * @see org.eclipse.update.configuration.LocalSystemInfo
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IVolume extends IAdaptable {
+
+ /**
+ * Returns the available free space on this volume.
+ * Returns the amount of free space available to this
+ * user on the volume. The
+ * method takes into account any space quotas or other
+ * native mechanisms that may restrict space usage
+ * on a given volume.
+ * @return the amount of free space available (in units
+ * of Kbyte), or an indication the size is not known
+ * @see LocalSystemInfo#SIZE_UNKNOWN
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 long getFreeSpace();
+
+ /**
+ * returns volume label.
+ * Returns the label of the volume.
+ * @return volume label (as string), or <code>null</code> if
+ * the label cannot be determined.
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 String getLabel();
+
+ /**
+ * Returns volume type.
+ * Returns the type of the volume.
+ * @return volume type
+ * @see LocalSystemInfo#VOLUME_UNKNOWN
+ * @see LocalSystemInfo#VOLUME_INVALID_PATH
+ * @see LocalSystemInfo#VOLUME_REMOVABLE
+ * @see LocalSystemInfo#VOLUME_FIXED
+ * @see LocalSystemInfo#VOLUME_REMOTE
+ * @see LocalSystemInfo#VOLUME_CDROM
+ * @see LocalSystemInfo#VOLUME_FLOPPY_3
+ * @see LocalSystemInfo#VOLUME_FLOPPY_5
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 int getType();
+
+ /**
+ * Returns the volume path.
+ * Returns the path that represents the mount point of the volume.
+ * @return mount point file
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 File getFile();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/LocalSystemInfo.java b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/LocalSystemInfo.java
new file mode 100644
index 0000000..038cb4f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/LocalSystemInfo.java
@@ -0,0 +1,426 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.configuration;
+
+import java.io.File;
+import java.util.ArrayList;
+
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.Volume;
+
+/**
+ * Utility class providing local file system information.
+ * The class attempts to load a native library implementation
+ * of its methods. If successful, the method calls are delegated
+ * to the native implementation. Otherwise a default non-native
+ * implementation is used. *
+ * <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>
+ * @see ILocalSystemInfoListener
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class LocalSystemInfo {
+
+ /**
+ * Indicates the amount of available free space is not known
+ *
+ * @see LocalSystemInfo#getFreeSpace(File)
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final long SIZE_UNKNOWN = -1;
+
+ /**
+ * Indicates the volume type is not known
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int VOLUME_UNKNOWN = -1;
+
+ /**
+ * Indicates the volume could not be determined from path
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int VOLUME_INVALID_PATH = -2;
+
+ /**
+ * Indicates the volume is removable (other than floppy disk)
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int VOLUME_REMOVABLE = 1;
+
+ /**
+ * Indicates the volume is fixed (hard drive)
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int VOLUME_FIXED = 2;
+
+ /**
+ * Indicates a remote (network) volume
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int VOLUME_REMOTE = 3;
+
+ /**
+ * Indicates a cdrom volume (compact disc)
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int VOLUME_CDROM = 4;
+
+ /**
+ * Indicates a ramdisk volume (memory)
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int VOLUME_RAMDISK = 5;
+
+ /**
+ * Indicates the volume is removable (floppy disk 5 1/4)
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int VOLUME_FLOPPY_5 = 6;
+
+ /**
+ * Indicates the volume is removable (floppy disk 3 1/2)
+ *
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int VOLUME_FLOPPY_3 = 7;
+
+ /**
+ * Indicates a new volume has been added
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int VOLUME_ADDED = 0;
+
+ /**
+ * Indicates a volume has been removed
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int VOLUME_REMOVED = 1;
+
+ /**
+ * Indicates a volume has been changed
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This field 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 static final int VOLUME_CHANGED = 2;
+
+
+ private static ArrayList listeners = new ArrayList();
+ private static boolean hasNatives = false;
+ static {
+ try {
+ System.loadLibrary("update"); //$NON-NLS-1$
+ hasNatives = true;
+ } catch (UnsatisfiedLinkError e) {
+ UpdateCore.warn("Unable to load native library 'update'."); //$NON-NLS-1$
+ hasNatives = false;
+ }
+ }
+
+ /**
+ * Determines available free space on a volume.
+ * Returns the amount of free space available to this
+ * user on the volume containing the specified path. The
+ * method takes into account any space quotas or other
+ * native mechanisms that may restrict space usage
+ * on a given volume.
+ * @param path file path. May contain path elements beyond
+ * the volume "root"
+ * @return the amount of free space available (in units
+ * of Kbyte), or an indication the size is not known
+ * @see LocalSystemInfo#SIZE_UNKNOWN
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 static long getFreeSpace(File path) {
+ if (hasNatives) {
+ try {
+ long bytes = nativeGetFreeSpace(path);
+ return (bytes!=0)?bytes/1024:0;
+ } catch (UnsatisfiedLinkError e) {
+ }
+ }
+ return SIZE_UNKNOWN;
+ }
+
+
+ /**
+ * Lists the file system volume.
+ * @return array of volume representing mount
+ * points, or <code>null</code> if none found
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 static IVolume[] getVolumes() {
+ String[] mountPoints = listMountPoints();
+ Volume[] vol = new Volume[0];
+ if (mountPoints!=null){
+ vol = new Volume[mountPoints.length];
+ for (int i = 0; i < mountPoints.length; i++) {
+ File root = new File(mountPoints[i]);
+ String label = getLabel(root);
+ int type = getType(root);
+ long size = getFreeSpace(root);
+ vol[i] = new Volume(root,label,type,size);
+ vol[i].markReadOnly();
+ }
+ } else {
+ UpdateCore.warn("Unable to find mount points"); //$NON-NLS-1$
+ // fallback
+ File [] roots = File.listRoots();
+ if (roots.length == 1) {
+ // just one root - skip it
+ File root = roots[0];
+ roots = root.listFiles();
+ }
+ vol = new Volume[roots.length];
+ for (int i = 0; i < roots.length; i++) {
+ vol[i] = new Volume(roots[i],null,LocalSystemInfo.VOLUME_UNKNOWN,LocalSystemInfo.SIZE_UNKNOWN);
+ vol[i].markReadOnly();
+ }
+ }
+ return vol;
+ }
+
+
+ /**
+ * Add local system change listener.
+ * Allows a listener to be added for monitoring changes
+ * in the local system information. The listener is notified
+ * each time there are relevant volume changes
+ * detected. This specifically includes changes to the
+ * list of volumes as a result of removable drive/ media
+ * operations (eg. CD insertion, removal), and changes to volume
+ * mount structure.
+ * @param listener change listener
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 static void addInfoListener(ILocalSystemInfoListener listener) {
+ if (!listeners.contains(listener))
+ listeners.add(listener);
+ }
+
+ /**
+ * Remove local system change listener
+ * @param listener change listener
+ * @since 2.0
+ * <p>
+ * <b>Note:</b> This method 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 static void removeInfoListener(ILocalSystemInfoListener listener) {
+ listeners.remove(listener);
+ }
+
+ /**
+ * Notify listeners of change.
+ *
+ * @param volume the volume representing the
+ * change file system structure. Any current paths beyond
+ * the specified "root" file of the volume are assumed to be invalidated.
+ * @param changeType type of the change that occured.
+ * @see LocalSystemInfo#VOLUME_ADDED
+ * @see LocalSystemInfo#VOLUME_REMOVED
+ * @see LocalSystemInfo#VOLUME_CHANGED
+ * <p>
+ * <b>Note:</b> This method 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 static void fireSystemInfoChanged(IVolume volume, int changeType) {
+ for (int i=0; i< listeners.size(); i++) {
+ ((ILocalSystemInfoListener)listeners.get(i)).systemInfoChanged(volume,changeType);
+ }
+ }
+
+ /*
+ * Determines volume label.
+ * Returns the label of the volume containing the specified
+ * path.
+ * @param path file path. May contain path elements beyond
+ * the volume "root"
+ * @return volume label (as string), or <code>null</code> if
+ * the label cannot be determined.
+ * @since 2.0
+ */
+ private static String getLabel(File path) {
+ if (hasNatives) {
+ try {
+ return nativeGetLabel(path);
+ } catch (UnsatisfiedLinkError e) {
+ }
+ }
+ return null;
+ }
+
+ /*
+ * Determines volume type.
+ * Returns the type of the volume containing the specified
+ * path.
+ * @param path file path. May contain path elements beyond
+ * the volume "root"
+ * @return volume type
+ * @see LocalSystemInfo#VOLUME_UNKNOWN
+ * @see LocalSystemInfo#VOLUME_INVALID_PATH
+ * @see LocalSystemInfo#VOLUME_REMOVABLE
+ * @see LocalSystemInfo#VOLUME_FIXED
+ * @see LocalSystemInfo#VOLUME_REMOTE
+ * @see LocalSystemInfo#VOLUME_CDROM
+ * @see LocalSystemInfo#VOLUME_FLOPPY_3
+ * @see LocalSystemInfo#VOLUME_FLOPPY_5
+ * @since 2.0
+ */
+ private static int getType(File path) {
+ if (hasNatives) {
+ try {
+ return nativeGetType(path);
+ } catch (UnsatisfiedLinkError e) {
+ }
+ }
+ return VOLUME_UNKNOWN;
+ }
+
+ /*
+ * Lists the file system mount points.
+ * @return array of absolute file paths representing mount
+ * points, or <code>null</code> if none found
+ * @since 2.0
+ */
+ private static String[] listMountPoints() {
+ if (hasNatives) {
+ try {
+ String[] mountPoints = nativeListMountPoints();
+ return mountPoints;
+ } catch (UnsatisfiedLinkError e) {
+ }
+ }
+ return null;
+ }
+
+ /*
+ * Native implementations.
+ */
+ private static native long nativeGetFreeSpace(File path);
+ private static native String nativeGetLabel(File path);
+ private static native int nativeGetType(File path);
+ private static native String[] nativeListMountPoints();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/configuration/package.html b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/package.html
new file mode 100644
index 0000000..a35e812
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/configuration/package.html
@@ -0,0 +1,23 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="Author" content="IBM">
+ <meta name="GENERATOR" content="Mozilla/4.72 [en] (Windows NT 5.0; U) [Netscape]">
+ <title>Package-level Javadoc</title>
+</head>
+<body>
+Provides support for accessing local installation
+information.
+<h2>
+Package Specification</h2>
+This package contains interfaces for accessing and manipulating the local
+system installation and configuration information. In general, users extending
+the update support by writing additional feature and site implementation
+do not need to make use of interfaces defined in this package.
+<p>
+<b>Note:</b> This package has been deprecated and will be deleted in a future
+release. See bug 311590 for details.
+</p>
+</body>
+</html>
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/ArchiveReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/ArchiveReference.java
new file mode 100644
index 0000000..0ee0248
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/ArchiveReference.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.update.core.model.ArchiveReferenceModel;
+
+/**
+ * Convenience implementation of a site archive.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.IArchiveReference
+ * @see org.eclipse.update.core.model.ArchiveReferenceModel
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class ArchiveReference
+ extends ArchiveReferenceModel
+ implements IArchiveReference {
+
+ /**
+ * Constructor for ArchiveReference
+ * @since 2.0
+ */
+ public ArchiveReference() {
+ super();
+ }
+
+ /**
+ * @see Object#toString()
+ * @since 2.0
+ */
+ public String toString() {
+ String result = "IArchiveReference: "; //$NON-NLS-1$
+ result =
+ result
+ + ((getPath() == null)
+ ? getURL().toExternalForm()
+ : getPath() + " : " + getURL().toExternalForm()); //$NON-NLS-1$
+ return result;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/BaseFeatureFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/BaseFeatureFactory.java
new file mode 100644
index 0000000..79fe2df
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/BaseFeatureFactory.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.update.core.model.FeatureModel;
+import org.eclipse.update.core.model.FeatureModelFactory;
+import org.eclipse.update.core.model.ImportModel;
+import org.eclipse.update.core.model.IncludedFeatureReferenceModel;
+import org.eclipse.update.core.model.InstallHandlerEntryModel;
+import org.eclipse.update.core.model.NonPluginEntryModel;
+import org.eclipse.update.core.model.PluginEntryModel;
+import org.eclipse.update.core.model.URLEntryModel;
+
+/**
+ * Base implementation of a feature factory.
+ * The factory is responsible for constructing the correct
+ * concrete implementation of the model objects for each particular
+ * feature type. This class creates model objects that correspond
+ * to the concrete implementation classes provided in this package.
+ * The actual feature creation method is subclass responsibility.
+ * <p>
+ * This class must be subclassed 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>
+ * @see org.eclipse.update.core.IFeatureFactory
+ * @see org.eclipse.update.core.model.FeatureModelFactory
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public abstract class BaseFeatureFactory extends FeatureModelFactory implements IFeatureFactory {
+
+ /**
+ *
+ * @deprecated implement createFeature(URL, ISite, IProgressMonitor) instead
+ * @see IFeatureFactory#createFeature(URL,ISite)
+ * @since 2.0
+ */
+ public IFeature createFeature(URL url, ISite site) throws CoreException {
+ return createFeature(url, site, null);
+ }
+
+ /**
+ * Create feature. Implementation of this method must be provided by
+ * subclass
+ *
+ * @see IFeatureFactory#createFeature(URL,ISite,IProgressMonitor)
+ * @since 2.0
+ */
+ public abstract IFeature createFeature(URL url, ISite site, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Create a concrete implementation of feature model.
+ *
+ * @see Feature
+ * @return feature model
+ * @since 2.0
+ */
+ public FeatureModel createFeatureModel() {
+ return new Feature();
+ }
+
+ /**
+ * Create a concrete implementation of included feature reference model.
+ *
+ * @see IncludedFeatureReference
+ * @return feature model
+ * @since 2.1
+ */
+ public IncludedFeatureReferenceModel createIncludedFeatureReferenceModel() {
+ return new IncludedFeatureReference();
+ }
+
+ /**
+ * Create a concrete implementation of install handler model.
+ *
+ * @see InstallHandlerEntry
+ * @return install handler entry model
+ * @since 2.0
+ */
+ public InstallHandlerEntryModel createInstallHandlerEntryModel() {
+ return new InstallHandlerEntry();
+ }
+
+ /**
+ * Create a concrete implementation of import dependency model.
+ *
+ * @see Import
+ * @return import dependency model
+ * @since 2.0
+ */
+ public ImportModel createImportModel() {
+ return new Import();
+ }
+
+ /**
+ * Create a concrete implementation of plug-in entry model.
+ *
+ * @see PluginEntry
+ * @return plug-in entry model
+ * @since 2.0
+ */
+ public PluginEntryModel createPluginEntryModel() {
+ return new PluginEntry();
+ }
+
+ /**
+ * Create a concrete implementation of non-plug-in entry model.
+ *
+ * @see NonPluginEntry
+ * @return non-plug-in entry model
+ * @since 2.0
+ */
+ public NonPluginEntryModel createNonPluginEntryModel() {
+ return new NonPluginEntry();
+ }
+
+ /**
+ * Create a concrete implementation of annotated URL model.
+ *
+ * @see URLEntry
+ * @return annotated URL model
+ * @since 2.0
+ */
+ public URLEntryModel createURLEntryModel() {
+ return new URLEntry();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/BaseInstallHandler.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/BaseInstallHandler.java
new file mode 100644
index 0000000..a3f5f11
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/BaseInstallHandler.java
@@ -0,0 +1,252 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Base implementation of an install handler.
+ * This is a convenience implementation of an install handler with
+ * null implementation of its methods. It allows subclasses to selectively
+ * implement only the methods required for their installation tasks.
+ * <p>
+ * This class should be subclassed 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>
+ * @see org.eclipse.update.core.IInstallHandler
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class BaseInstallHandler implements IInstallHandler {
+
+ /**
+ * Update action type
+ *
+ * @see IInstallHandler#HANDLER_ACTION_INSTALL
+ * @see IInstallHandler#HANDLER_ACTION_CONFIGURE
+ * @see IInstallHandler#HANDLER_ACTION_UNCONFIGURE
+ * @see IInstallHandler#HANDLER_ACTION_UNINSTALL
+ * @since 2.0
+ */
+ protected int type;
+
+ /**
+ * The target of the action
+ * @since 2.0
+ */
+ protected IFeature feature;
+
+ /**
+ * Model entry that defines this handler
+ *
+ * @since 2.0
+ */
+ protected IInstallHandlerEntry entry;
+
+ /**
+ * Optional progress monitor, can be <code>null</code>
+ *
+ * @since 2.0
+ */
+ protected InstallMonitor monitor;
+
+ /**
+ * Plug-in entries downloaded
+ *
+ * @see IInstallHandler#HANDLER_ACTION_INSTALL
+ * @since 2.0
+ */
+ protected IPluginEntry[] pluginEntries;
+
+ /**
+ * Non-plug-in entries downloaded
+ *
+ * @see IInstallHandler#HANDLER_ACTION_INSTALL
+ * @since 2.0
+ */
+ protected INonPluginEntry[] nonPluginEntries;
+
+ /**
+ * Indicates if handler has been initialized
+ *
+ * @since 2.0
+ */
+ protected boolean initialized = false;
+
+ /**
+ * Initialize the install handler.
+ *
+ * @see IInstallHandler#initialize(int, IFeature, IInstallHandlerEntry, InstallMonitor)
+ * @since 2.0
+ */
+ public void initialize(
+ int type,
+ IFeature feature,
+ IInstallHandlerEntry entry,
+ InstallMonitor monitor)
+ throws CoreException {
+
+ if (this.initialized)
+ return;
+ else {
+ if (feature == null)
+ throw new IllegalArgumentException();
+ this.type = type;
+ this.feature = feature;
+ this.entry = entry;
+ this.monitor = monitor;
+ this.initialized = true;
+ }
+ }
+
+ /**
+ * Called at the start of the install action.
+ *
+ * @see IInstallHandler#installInitiated
+ * @since 2.0
+ */
+ public void installInitiated() throws CoreException {
+ }
+
+ /**
+ * Called after files corresponding to plug-in entries have been downloaded,
+ * but before they are actually unpacked and installed.
+ *
+ * @see IInstallHandler#pluginsDownloaded(IPluginEntry[])
+ * @since 2.0
+ */
+ public void pluginsDownloaded(IPluginEntry[] plugins) throws CoreException {
+
+ this.pluginEntries = plugins;
+ }
+
+ /**
+ * Called after files corresponding to non-plug-in entries have been
+ * downloaded.
+ *
+ * @see IInstallHandler#nonPluginDataDownloaded(INonPluginEntry[], IVerificationListener)
+ * @since 2.0
+ */
+ public void nonPluginDataDownloaded(
+ INonPluginEntry[] nonPluginData,
+ IVerificationListener listener)
+ throws CoreException {
+
+ this.nonPluginEntries = nonPluginData;
+ }
+
+ /**
+ * Called after the feature files and any downloaded plug-ins have
+ * been installed.
+ *
+ * @see IInstallHandler#completeInstall(IFeatureContentConsumer)
+ * @since 2.0
+ */
+ public void completeInstall(IFeatureContentConsumer consumer)
+ throws CoreException {
+ }
+
+ /**
+ * Called at the end of the install action.
+ *
+ * @see IInstallHandler#installCompleted(boolean)
+ * @since 2.0
+ */
+ public void installCompleted(boolean success) throws CoreException {
+ }
+
+ /**
+ * Called at the start of the configure action.
+ *
+ * @see IInstallHandler#configureInitiated()
+ * @since 2.0
+ */
+ public void configureInitiated() throws CoreException {
+ }
+
+ /**
+ * Called after the feature has been configured.
+ *
+ * @see IInstallHandler#completeConfigure()
+ * @since 2.0
+ */
+ public void completeConfigure() throws CoreException {
+ }
+
+ /**
+ * Called at the end of the configure action.
+ *
+ * @see IInstallHandler#configureCompleted(boolean)
+ * @since 2.0
+ */
+ public void configureCompleted(boolean success) throws CoreException {
+ }
+
+ /**
+ * Called at the start of the unconfigure action.
+ *
+ * @see IInstallHandler#unconfigureInitiated()
+ * @since 2.0
+ */
+ public void unconfigureInitiated() throws CoreException {
+ }
+
+ /**
+ * Called after the feature has been unconfigured.
+ *
+ * @see IInstallHandler#completeUnconfigure()
+ * @since 2.0
+ */
+ public void completeUnconfigure() throws CoreException {
+ }
+
+ /**
+ * Called at the end of the unconfigure action.
+ *
+ * @see IInstallHandler#unconfigureCompleted(boolean)
+ * @since 2.0
+ */
+ public void unconfigureCompleted(boolean success) throws CoreException {
+ }
+
+ /**
+ * Called at the start of the uninstall action.
+ *
+ * @see IInstallHandler#uninstallInitiated()
+ * @since 2.0
+ */
+ public void uninstallInitiated() throws CoreException {
+ }
+
+ /**
+ * Called after the feature has been uninstalled.
+ *
+ * @see IInstallHandler#completeUninstall()
+ * @since 2.0
+ */
+ public void completeUninstall() throws CoreException {
+ }
+
+ /**
+ * Called at the end of the uninstall action.
+ *
+ * @see IInstallHandler#uninstallCompleted(boolean)
+ * @since 2.0
+ */
+ public void uninstallCompleted(boolean success) throws CoreException {
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/BaseSiteFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/BaseSiteFactory.java
new file mode 100644
index 0000000..650bd1d
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/BaseSiteFactory.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.model.ArchiveReferenceModel;
+import org.eclipse.update.core.model.CategoryModel;
+import org.eclipse.update.core.model.InvalidSiteTypeException;
+import org.eclipse.update.core.model.SiteModel;
+import org.eclipse.update.core.model.SiteModelFactory;
+import org.eclipse.update.core.model.URLEntryModel;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+import org.eclipse.update.internal.core.connection.ConnectionFactory;
+import org.eclipse.update.internal.core.connection.IResponse;
+
+/**
+ * Base implementation of a site factory.
+ * The factory is responsible for constructing the correct
+ * concrete implementation of the model objects for each particular
+ * site type. This class creates model objects that correspond
+ * to the concrete implementation classes provided in this package.
+ * The actual site creation method is subclass responsibility.
+ * <p>
+ * This class must be subclassed 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>
+ * @see org.eclipse.update.core.ISiteFactory
+ * @see org.eclipse.update.core.model.SiteModelFactory
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public abstract class BaseSiteFactory extends SiteModelFactory implements ISiteFactory {
+
+
+ /**
+ * Create site. Implementation of this method must be provided by
+ * subclass
+ *
+ * @see ISiteFactory#createSite(URL)
+ * @since 2.0
+ */
+ public abstract ISite createSite(URL url) throws CoreException, InvalidSiteTypeException;
+
+ /**
+ * Helper method to access resouce bundle for site. The default
+ * implementation attempts to load the appropriately localized
+ * site.properties file.
+ *
+ * @param url base URL used to load the resource bundle.
+ * @return resource bundle, or <code>null</code>.
+ * @since 2.0
+ */
+ protected ResourceBundle getResourceBundle(URL url) {
+ ResourceBundle bundle = null;
+
+ try {
+ url = UpdateManagerUtils.asDirectoryURL(url);
+ ClassLoader l = new URLClassLoader(new URL[] { url }, null);
+ bundle = ResourceBundle.getBundle(Site.SITE_FILE, Locale.getDefault(), l);
+ } catch (MissingResourceException e) {
+ UpdateCore.warn(e.getLocalizedMessage() + ":" + url.toExternalForm()); //$NON-NLS-1$
+ } catch (MalformedURLException e) {
+ UpdateCore.warn(NLS.bind(Messages.BaseSiteFactory_CannotRetriveParentDirectory, (new String[] { url.toExternalForm() })));
+ }
+
+ return bundle;
+ }
+
+ /**
+ * Create a concrete implementation of site model.
+ *
+ * @see Site
+ * @return site model
+ * @since 2.0
+ */
+ public SiteModel createSiteMapModel() {
+ return new Site();
+ }
+
+
+ /**
+ * Create a concrete implementation of feature reference model.
+ *
+ * @see FeatureReference
+ * @return feature reference model
+ * @since 2.0
+ */
+ public SiteFeatureReferenceModel createFeatureReferenceModel() {
+ return new SiteFeatureReference();
+ }
+
+ /**
+ * Create a concrete implementation of archive reference model.
+ *
+ * @see ArchiveReference
+ * @return archive reference model
+ * @since 2.0
+ */
+ public ArchiveReferenceModel createArchiveReferenceModel() {
+ return new ArchiveReference();
+ }
+
+
+ /**
+ * Create a concrete implementation of annotated URL model.
+ *
+ * @see URLEntry
+ * @return annotated URL model
+ * @since 2.0
+ */
+ public URLEntryModel createURLEntryModel() {
+ return new URLEntry();
+ }
+
+
+ /**
+ * Create a concrete implementation of category model.
+ *
+ * @see Category
+ * @return category model
+ * @since 2.0
+ */
+ public CategoryModel createSiteCategoryModel() {
+ return new Category();
+ }
+
+ /**
+ * Open a stream on a URL.
+ * manages a time out if the connection is locked or fails
+ *
+ * @param resolvedURL
+ * @return InputStream
+ */
+ protected InputStream openStream(URL resolvedURL) throws IOException {
+ IResponse response = ConnectionFactory.get(resolvedURL);
+ return response.getInputStream();
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/Category.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/Category.java
new file mode 100644
index 0000000..73d1d56
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/Category.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.update.core.model.CategoryModel;
+
+/**
+ * Convenience implementation of feature category definition.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.ICategory
+ * @see org.eclipse.update.core.model.CategoryModel
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class Category extends CategoryModel implements ICategory {
+
+ /**
+ * Default Constructor
+ */
+ public Category() {
+ }
+
+ /**
+ * Constructor
+ */
+ public Category(String name, String label) {
+ setName(name);
+ setLabel(label);
+ }
+
+ /**
+ * Retrieve the detailed category description
+ * @see ICategory#getDescription()
+ */
+ public IURLEntry getDescription() {
+ return (IURLEntry) getDescriptionModel();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/ContentReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/ContentReference.java
new file mode 100644
index 0000000..632e409
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/ContentReference.java
@@ -0,0 +1,340 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.internal.core.FatalIOException;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.URLEncoder;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+import org.eclipse.update.internal.core.connection.ConnectionFactory;
+import org.eclipse.update.internal.core.connection.HttpResponse;
+import org.eclipse.update.internal.core.connection.IResponse;
+
+/**
+ * Content reference implements a general access wrapper
+ * to feature and site content. The reference specifies
+ * a "symbolic" path identifier for the content, and the actual
+ * reference as a file, or a URL.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.JarContentReference
+ * @see org.eclipse.update.core.JarEntryContentReference
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class ContentReference {
+
+ /**
+ * Unknown size indication
+ * @since 2.0
+ */
+ public static final long UNKNOWN_SIZE = -1;
+
+ /**
+ * Default executable permission when installing a content reference
+ * Will add executable bit if necessary
+ *
+ * @since 2.0.1
+ */
+ public static final int DEFAULT_EXECUTABLE_PERMISSION = -1;
+
+ private static final String FILE_URL_PROTOCOL = "file"; //$NON-NLS-1$
+
+ private String id;
+ private URL url; // reference is either URL reference *OR*
+ private File file; // local file reference
+ private IResponse response;
+ private int permission;
+ private long length;
+
+ // <true> if a copy of a Contentreferenec in a temp local directory
+ private boolean tempLocal = false;
+
+ private long lastModified;
+
+ /**
+ * Create content reference from URL.
+ *
+ * @param id "symbolic" path identifier
+ * @param url actual referenced URL
+ * @since 2.0
+ */
+ public ContentReference(String id, URL url) {
+ this.id = (id == null ? "" : id); //$NON-NLS-1$
+ this.url = url; // can be null
+ this.file = null;
+ }
+
+ /**
+ * Create content reference from file.
+ *
+ * @param id "symbolic" path identifier
+ * @param file actual referenced file
+ * @since 2.0
+ */
+ public ContentReference(String id, File file) {
+ this.id = (id == null ? "" : id); //$NON-NLS-1$
+ this.file = file; // can be null
+ this.url = null;
+ }
+
+ /**
+ * A factory method to create a content reference of
+ * the same type.
+ *
+ * @param id "symbolic" path identifier
+ * @param file actual referenced file
+ * @return content reference of the same type
+ * @since 2.0
+ */
+ public ContentReference createContentReference(String id, File file) {
+ return new ContentReference(id, file,true);
+ }
+ /**
+ *
+ */
+ private ContentReference(String id, File file, boolean b) {
+ this(id,file);
+ setTempLocal(b);
+ }
+
+ /**
+ * Retrieves the "symbolic" path identifier for the reference.
+ *
+ * @return "symbolic" path identifier
+ * @since 2.0
+ */
+ public String getIdentifier() {
+ return id;
+ }
+
+ /**
+ * Creates an input stream for the reference.
+ *
+ * @return input stream
+ * @exception IOException unable to create stream
+ * @since 2.0
+ */
+ public InputStream getInputStream() throws IOException {
+ if (file != null)
+ return new FileInputStream(file);
+ else if (url != null) {
+ if (response == null) {
+ URL resolvedURL = URLEncoder.encode(url);
+ response = ConnectionFactory.get(resolvedURL);
+ UpdateManagerUtils.checkConnectionResult(response,resolvedURL);
+ }
+ InputStream is=response.getInputStream();
+ length=response.getContentLength();
+ return is;
+ } else
+ throw new FatalIOException(NLS.bind(Messages.ContentReference_UnableToCreateInputStream, (new String[] { this.toString() })));
+ }
+ /**
+ * Creates an input stream for the reference.
+ *
+ * @return input stream
+ * @exception IOException unable to create stream
+ * @since 2.0
+ */
+ InputStream getPartialInputStream(long offset) throws IOException {
+ if (url != null && "http".equals(url.getProtocol())) { //$NON-NLS-1$
+ URL resolvedURL = URLEncoder.encode(url);
+ response = ConnectionFactory.get(resolvedURL);
+ if(response instanceof HttpResponse)
+ ((HttpResponse)response).setOffset(offset);
+ UpdateManagerUtils.checkConnectionResult(response,resolvedURL);
+ InputStream is = response.getInputStream();
+ length=offset + response.getContentLength();
+ return is;
+ } else
+ throw new FatalIOException(NLS.bind(Messages.ContentReference_UnableToCreateInputStream, (new String[] { this.toString() })));
+ }
+
+ /**
+ * Returns the size of the referenced input, if it can be determined.
+ *
+ * @return input size, or @see #UNKNOWN_SIZE if size cannot be determined.
+ * @since 2.0
+ */
+ public long getInputSize() throws IOException {
+ if (length>0)
+ return length;
+ if (file != null)
+ return file.length();
+ else if (url != null) {
+ if (response == null) {
+ URL resolvedURL = null;
+ try {
+ resolvedURL = URLEncoder.encode(url);
+ response = ConnectionFactory.get(resolvedURL);
+ } catch (IOException e) {
+ return ContentReference.UNKNOWN_SIZE;
+ }
+ UpdateManagerUtils.checkConnectionResult(response,resolvedURL);
+ }
+ long size = response.getContentLength();
+ return size == -1 ? ContentReference.UNKNOWN_SIZE : size;
+ } else
+ return ContentReference.UNKNOWN_SIZE;
+ }
+
+ /**
+ * Indicates whether the reference is a local file reference.
+ *
+ * @return <code>true</code> if the reference is local,
+ * otherwise <code>false</code>
+ * @since 2.0
+ */
+ public boolean isLocalReference() {
+ /*if (file != null)
+ return true;
+ else if (url != null)
+ return FILE_URL_PROTOCOL.equals(url.getProtocol());
+ else
+ return false;*/
+ // only temp files are considered local
+ return tempLocal;
+ }
+
+ /**
+ * Returns the content reference as a file. Note, that this method
+ * <b>does not</b> cause the file to be downloaded if it
+ * is not already local.
+ *
+ * @return reference as file
+ * @exception IOException reference cannot be returned as file
+ * @since 2.0
+ */
+ public File asFile() throws IOException {
+ if (file != null)
+ return file;
+
+ if (url != null && FILE_URL_PROTOCOL.equals(url.getProtocol())) {
+ File result = new File(url.getFile());
+ if (result.exists())
+ return result;
+ else
+ throw new IOException(NLS.bind(Messages.ContentReference_FileDoesNotExist, (new String[] { this.toString() })));
+ }
+
+ throw new IOException(NLS.bind(Messages.ContentReference_UnableToReturnReferenceAsFile, (new String[] { this.toString() })));
+ }
+
+ /**
+ * Returns the content reference as a URL.
+ *
+ * @return reference as URL
+ * @exception IOException reference cannot be returned as URL
+ * @since 2.0
+ */
+ public URL asURL() throws IOException {
+ if (url != null)
+ return url;
+
+ if (file != null)
+ return file.toURL();
+
+ throw new FatalIOException(NLS.bind(Messages.ContentReference_UnableToReturnReferenceAsURL, (new String[] { this.toString() })));
+ }
+
+ /**
+ * Return string representation of this reference.
+ *
+ * @return string representation
+ * @since 2.0
+ */
+ public String toString() {
+ if (file != null)
+ return file.getAbsolutePath();
+ else
+ return url.toExternalForm();
+ }
+ /**
+ * Returns the permission for this file.
+ *
+ * @return the content reference permission
+ * @see #DEFAULT_EXECUTABLE_PERMISSION
+ * @since 2.0.1
+ */
+ public int getPermission() {
+ return permission;
+ }
+
+ /**
+ * Sets the permission of this content reference.
+ *
+ * @param permission The permission to set
+ */
+ public void setPermission(int permission) {
+ this.permission = permission;
+ }
+
+ /**
+ * Sets if a content reference is considered local
+ *
+ * @param tempLocal <code>true</code> if the file is considered local
+ */
+ protected void setTempLocal(boolean tempLocal) {
+ this.tempLocal = tempLocal;
+ }
+
+ /**
+ * Sets the timestamp the content was last modified.
+ * @param timestamp
+ * @since 3.0
+ */
+ public void setLastModified(long timestamp) {
+ this.lastModified = timestamp;
+ }
+
+ /**
+ * Returns the timestamp when the content was last modified
+ * @return the timestamp
+ * @since 3.0
+ */
+ public long getLastModified() {
+ if (lastModified == 0) {
+ if (file != null)
+ lastModified = file.lastModified();
+ else if (url != null) {
+ if (response == null) {
+ try {
+ URL resolvedURL = URLEncoder.encode(url);
+ response = ConnectionFactory.get(resolvedURL);
+ } catch (MalformedURLException e) {
+ // return 0
+ } catch (IOException e) {
+ // return 0
+ }
+ }
+ lastModified = response.getLastModified();
+ }
+ }
+ return lastModified;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/Feature.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/Feature.java
new file mode 100644
index 0000000..329ef57
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/Feature.java
@@ -0,0 +1,1163 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.core;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.model.ContentEntryModel;
+import org.eclipse.update.core.model.FeatureModel;
+import org.eclipse.update.core.model.FeatureReferenceModel;
+import org.eclipse.update.core.model.ImportModel;
+import org.eclipse.update.core.model.InstallAbortedException;
+import org.eclipse.update.core.model.NonPluginEntryModel;
+import org.eclipse.update.core.model.PluginEntryModel;
+import org.eclipse.update.core.model.URLEntryModel;
+import org.eclipse.update.internal.core.ErrorRecoveryLog;
+import org.eclipse.update.internal.core.InstallHandlerProxy;
+import org.eclipse.update.internal.core.InstallRegistry;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.TargetFeature;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+import org.eclipse.update.internal.core.UpdateSiteIncludedFeatureReference;
+
+/**
+ * Convenience implementation of a feature.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.IFeature
+ * @see org.eclipse.update.core.model.FeatureModel
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class Feature extends FeatureModel implements IFeature {
+
+ /**
+ * Simple file name of the default feature manifest file
+ * @since 2.0
+ */
+ public static final String FEATURE_FILE = "feature"; //$NON-NLS-1$
+
+ /**
+ * File extension of the default feature manifest file
+ * @since 2.0
+ */
+ public static final String FEATURE_XML = FEATURE_FILE + ".xml"; //$NON-NLS-1$
+
+ private ISite site; // feature site
+ private IFeatureContentProvider featureContentProvider; // content provider
+ private List /*of IFeatureReference*/
+ includedFeatureReferences;
+
+ //PERF: new instance variable
+ private VersionedIdentifier versionId;
+
+ private InstallAbortedException abortedException = null;
+
+ /**
+ * Feature default constructor
+ *
+ * @since 2.0
+ */
+ public Feature() {
+ }
+
+ /**
+ * Compares two features for equality
+ *
+ * @param object feature object to compare with
+ * @return <code>true</code> if the two features are equal,
+ * <code>false</code> otherwise
+ * @since 2.0
+ */
+ public boolean equals(Object object) {
+ if (!(object instanceof IFeature))
+ return false;
+ IFeature f = (IFeature) object;
+ return getVersionedIdentifier().equals(f.getVersionedIdentifier());
+ }
+
+ /**
+ * Returns the feature identifier.
+ *
+ * @see IFeature#getVersionedIdentifier()
+ * @since 2.0
+ */
+ public VersionedIdentifier getVersionedIdentifier() {
+ if (versionId != null)
+ return versionId;
+
+ String id = getFeatureIdentifier();
+ String ver = getFeatureVersion();
+ if (id != null && ver != null) {
+ try {
+ versionId = new VersionedIdentifier(id, ver);
+ return versionId;
+ } catch (Exception e) {
+ UpdateCore.warn(
+ "Unable to create versioned identifier:" + id + ":" + ver); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ versionId = new VersionedIdentifier(getURL().toExternalForm(), null);
+ return versionId;
+ }
+
+ /**
+ * Returns the site this feature is associated with.
+ *
+ * @see IFeature#getSite()
+ * @since 2.0
+ */
+ public ISite getSite() {
+ return site;
+ }
+
+ /**
+ * Returns the feature URL.
+ *
+ * @see IFeature#getURL()
+ * @since 2.0
+ */
+ public URL getURL() {
+ IFeatureContentProvider contentProvider = null;
+ try {
+ contentProvider = getFeatureContentProvider();
+ } catch (CoreException e) {
+ UpdateCore.warn("No content Provider", e); //$NON-NLS-1$
+ }
+ return (contentProvider != null) ? contentProvider.getURL() : null;
+ }
+
+ /**
+ * Returns an information entry referencing the location of the
+ * feature update site.
+ *
+ * @see IFeature#getUpdateSiteEntry()
+ * @since 2.0
+ */
+ public IURLEntry getUpdateSiteEntry() {
+ return (IURLEntry) getUpdateSiteEntryModel();
+ }
+
+ /**
+ * Return an array of information entries referencing locations of other
+ * update sites.
+ *
+ * @see IFeature#getDiscoverySiteEntries()
+ * @since 2.0
+ */
+ public IURLEntry[] getDiscoverySiteEntries() {
+ URLEntryModel[] result = getDiscoverySiteEntryModels();
+ if (result.length == 0)
+ return new IURLEntry[0];
+ else
+ return (IURLEntry[]) result;
+ }
+
+ /**
+ * Returns and optional custom install handler entry.
+ *
+ * @see IFeature#getInstallHandlerEntry()
+ * @since 2.0
+ */
+ public IInstallHandlerEntry getInstallHandlerEntry() {
+ return (IInstallHandlerEntry) getInstallHandlerModel();
+ }
+
+ /**
+ * Returns the feature description.
+ *
+ * @see IFeature#getDescription()
+ * @since 2.0
+ */
+ public IURLEntry getDescription() {
+ return (IURLEntry) getDescriptionModel();
+ }
+
+ /**
+ * Returns the copyright information for the feature.
+ *
+ * @see IFeature#getCopyright()
+ * @since 2.0
+ */
+ public IURLEntry getCopyright() {
+ return (IURLEntry) getCopyrightModel();
+ }
+
+ /**
+ * Returns the license information for the feature.
+ *
+ * @see IFeature#getLicense()
+ * @since 2.0
+ */
+ public IURLEntry getLicense() {
+ return (IURLEntry) getLicenseModel();
+ }
+
+ /**
+ * Return optional image for the feature.
+ *
+ * @see IFeature#getImage()
+ * @since 2.0
+ */
+ public URL getImage() {
+ return getImageURL();
+ }
+
+ /**
+ * Return a list of plug-in dependencies for this feature.
+ *
+ * @see IFeature#getRawImports()
+ * @since 2.0
+ */
+ public IImport[] getRawImports() {
+ ImportModel[] result = getImportModels();
+ if (result.length == 0)
+ return new IImport[0];
+ else
+ return (IImport[]) result;
+ }
+
+ /**
+ * Install the contents of this feature into the specified target feature.
+ * This method is a reference implementation of the feature installation
+ * protocol. Other concrete feature implementation that override this
+ * method need to implement this protocol.
+ *
+ * @see IFeature#install(IFeature, IVerificationListener, IProgressMonitor)
+ * @since 2.0
+ */
+ public IFeatureReference install(
+ IFeature targetFeature,
+ IVerificationListener verificationListener,
+ IProgressMonitor progress)
+ throws InstallAbortedException, CoreException {
+ // call other API with all optional features, or setup variable meaning install all
+ return install(targetFeature, null, verificationListener, progress);
+ }
+
+ /**
+ * Install the contents of this feature into the specified target feature.
+ * This method is a reference implementation of the feature installation
+ * protocol. Other concrete feature implementation that override this
+ * method need to implement this protocol.
+ *
+ * @see IFeature#install(IFeature, IVerificationListener, IProgressMonitor)
+ * @since 2.0
+ */
+ public IFeatureReference install(
+ IFeature targetFeature,
+ IFeatureReference[] optionalfeatures,
+ IVerificationListener verificationListener,
+ IProgressMonitor progress)
+ throws InstallAbortedException, CoreException {
+
+ //DEBUG
+ debug("Installing...:" + getURL().toExternalForm()); //$NON-NLS-1$
+ ErrorRecoveryLog recoveryLog = ErrorRecoveryLog.getLog();
+
+ // make sure we have an InstallMonitor
+ InstallMonitor monitor;
+ if (progress == null)
+ monitor = new InstallMonitor(new NullProgressMonitor());
+ else if (progress instanceof InstallMonitor)
+ monitor = (InstallMonitor) progress;
+ else
+ monitor = new InstallMonitor(progress);
+
+ // Setup optional install handler
+ InstallHandlerProxy handler =
+ new InstallHandlerProxy(
+ IInstallHandler.HANDLER_ACTION_INSTALL,
+ this,
+ this.getInstallHandlerEntry(),
+ monitor);
+ boolean success = false;
+ Throwable originalException = null;
+ abortedException = null;
+
+ // Get source feature provider and verifier.
+ // Initialize target variables.
+ IFeatureContentProvider provider = getFeatureContentProvider();
+ IVerifier verifier = provider.getVerifier();
+ IFeatureReference result = null;
+ IFeatureReference alreadyInstalledFeature = null;
+ IFeatureContentConsumer consumer = null;
+ IPluginEntry[] targetSitePluginEntries = null;
+ ArrayList justInstalledPlugins = new ArrayList();
+
+ try {
+ // determine list of plugins to install
+ // find the intersection between the plugin entries already contained
+ // on the target site, and plugin entries packaged in source feature
+ IPluginEntry[] sourceFeaturePluginEntries = getPluginEntries();
+ ISite targetSite = targetFeature.getSite();
+ if (targetSite == null) {
+ debug("The site to install in is null"); //$NON-NLS-1$
+ targetSitePluginEntries = new IPluginEntry[0];
+ } else {
+ targetSitePluginEntries = targetSite.getPluginEntries();
+ }
+ IPluginEntry[] pluginsToInstall =
+ UpdateManagerUtils.diff(
+ sourceFeaturePluginEntries,
+ targetSitePluginEntries);
+ INonPluginEntry[] nonPluginsToInstall = getNonPluginEntries();
+
+ IFeatureReference[] children = getIncludedFeatureReferences();
+ if (optionalfeatures != null) {
+ children =
+ UpdateManagerUtils.optionalChildrenToInstall(
+ children,
+ optionalfeatures);
+ }
+
+ // determine number of monitor tasks
+ // 2 tasks for the feature jar (download/verify + install)
+ // + 2*n tasks for plugin entries (download/verify + install for each)
+ // + 1*m tasks per non-plugin data entry (download for each)
+ // + 1 task for custom non-plugin entry handling (1 for all combined)
+ // + 5*x tasks for children features (5 subtasks per install)
+ int taskCount =
+ 2
+ + 2 * pluginsToInstall.length
+ + nonPluginsToInstall.length
+ + 1
+ + 5 * children.length;
+ monitor.beginTask("", taskCount); //$NON-NLS-1$
+ SubProgressMonitor subMonitor = null;
+
+ // start log
+ recoveryLog.open(ErrorRecoveryLog.START_INSTALL_LOG);
+
+ // Start the installation tasks
+ handler.installInitiated();
+
+ // Download and verify feature archive(s)
+ ContentReference[] references =
+ provider.getFeatureEntryArchiveReferences(monitor);
+ verifyReferences(
+ verifier,
+ references,
+ monitor,
+ verificationListener,
+ true);
+ monitorWork(monitor, 1);
+
+ // Download and verify plugin archives
+ for (int i = 0; i < pluginsToInstall.length; i++) {
+ references = provider.getPluginEntryArchiveReferences(
+ pluginsToInstall[i], monitor);
+ verifyReferences(verifier, references, monitor,
+ verificationListener, false);
+ monitorWork(monitor, 1);
+ }
+
+ handler.pluginsDownloaded(pluginsToInstall);
+
+ Vector filteredPlugins = new Vector();
+ // Download non-plugin archives. Verification handled by optional
+ // install handler
+ for (int i = 0; i < nonPluginsToInstall.length; i++) {
+ if (handler.acceptNonPluginData(nonPluginsToInstall[i])) {
+ references = provider.getNonPluginEntryArchiveReferences(
+ nonPluginsToInstall[i], monitor);
+ monitorWork(monitor, 1);
+ filteredPlugins.add(nonPluginsToInstall[i]);
+ }
+ }
+ nonPluginsToInstall = (INonPluginEntry[]) filteredPlugins
+ .toArray(new INonPluginEntry[0]);
+ handler.nonPluginDataDownloaded(nonPluginsToInstall,
+ verificationListener);
+
+ // All archives are downloaded and verified. Get ready to install
+ consumer = targetFeature.getFeatureContentConsumer();
+
+ // install the children feature
+ // check if they are optional, and if they should be installed [2.0.1]
+ for (int i = 0; i < children.length; i++) {
+ IFeature childFeature = null;
+ try {
+ childFeature = children[i].getFeature(null);
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ }
+ if (childFeature != null) {
+ subMonitor = new SubProgressMonitor(monitor, 5);
+ ((Site) targetSite).install(// need to cast
+ childFeature,
+ optionalfeatures,
+ consumer,
+ verifier,
+ verificationListener,
+ subMonitor);
+ }
+ }
+
+ // Install plugin files
+ for (int i = 0; i < pluginsToInstall.length; i++) {
+ // if another feature has already installed this plugin, skip it
+ if (InstallRegistry.getInstance().isPluginJustInstalled(pluginsToInstall[i])) {
+ monitor.worked(1);
+ continue;
+ }
+ IContentConsumer pluginConsumer =
+ consumer.open(pluginsToInstall[i]);
+ // TODO consumer.open returns either
+ // SiteFilePackedPluginContentConsumer or SiteFilePluginContentConsumer
+ // and they are fed either
+ // PluginEntryArchiveReference or PluginEntryContentReferences
+ // it would be better to have one that is given PluginEntryArchiveReference
+ // but it would break external IContentConsumers
+
+ if(pluginsToInstall[i] instanceof PluginEntryModel && !((PluginEntryModel)pluginsToInstall[i]).isUnpack()){
+ // plugin can run from a jar
+ references = provider.getPluginEntryArchiveReferences(
+ pluginsToInstall[i], monitor);
+ } else{
+ // plugin must be unpacked
+ references =
+ provider.getPluginEntryContentReferences(
+ pluginsToInstall[i],
+ monitor);
+ }
+
+ String msg = ""; //$NON-NLS-1$
+ subMonitor = new SubProgressMonitor(monitor, 1);
+ VersionedIdentifier pluginVerId =
+ pluginsToInstall[i].getVersionedIdentifier();
+ String pluginID =
+ (pluginVerId == null) ? "" : pluginVerId.getIdentifier(); //$NON-NLS-1$
+ msg = NLS.bind(Messages.Feature_TaskInstallPluginFiles, (new String[] { pluginID }));
+
+ for (int j = 0; j < references.length; j++) {
+ setMonitorTaskName(
+ subMonitor,
+ msg + references[j].getIdentifier());
+ pluginConsumer.store(references[j], subMonitor);
+ }
+
+ if (monitor.isCanceled())
+ abort();
+ else {
+ justInstalledPlugins.add(pluginsToInstall[i]);
+ InstallRegistry.registerPlugin(pluginsToInstall[i]);
+ }
+ }
+
+ // check if we need to install feature files [16718]
+ // store will throw CoreException if another feature is already
+ // installed in the same place
+ alreadyInstalledFeature = featureAlreadyInstalled(targetSite);
+ // 18867
+ if (alreadyInstalledFeature == null) {
+ //Install feature files
+ references = provider.getFeatureEntryContentReferences(monitor);
+
+ String msg = ""; //$NON-NLS-1$
+ subMonitor = new SubProgressMonitor(monitor, 1);
+ msg = Messages.Feature_TaskInstallFeatureFiles;
+
+ for (int i = 0; i < references.length; i++) {
+ setMonitorTaskName(
+ subMonitor,
+ msg + " " + references[i].getIdentifier()); //$NON-NLS-1$
+ consumer.store(references[i], subMonitor);
+ }
+
+ if (monitor.isCanceled())
+ abort();
+ else
+ InstallRegistry.registerFeature(this);
+ } else {
+ if (monitor.isCanceled())
+ abort();
+ else
+ monitor.worked(1);
+ }
+
+ // call handler to complete installation (eg. handle non-plugin entries)
+ handler.completeInstall(consumer);
+ monitorWork(monitor, 1);
+
+ // indicate install success
+ success = true;
+
+ } catch (InstallAbortedException e) {
+ abortedException = e;
+ } catch (CoreException e) {
+ originalException = e;
+ } finally {
+ Exception newException = null;
+ try {
+ if (consumer != null) {
+ if (success) {
+ result = consumer.close();
+ if (result == null) {
+ result = alreadyInstalledFeature; // 18867
+ if (result != null
+ && optionalfeatures != null
+ && optionalfeatures.length > 0) {
+ // reinitialize as new optional children may have been installed
+ reinitializeFeature(result);
+ }
+ }
+ // close the log
+ recoveryLog.close(ErrorRecoveryLog.END_INSTALL_LOG);
+ } else {
+ // unregister the just installed plugins
+ for (int i=0; i<justInstalledPlugins.size(); i++)
+ InstallRegistry.unregisterPlugin(((IPluginEntry)justInstalledPlugins.get(i)));
+ consumer.abort();
+ }
+ }
+ handler.installCompleted(success);
+ // if abort is done, no need for the log to stay
+ recoveryLog.delete();
+ } catch (CoreException e) {
+ newException = e;
+ }
+
+ // original exception wins unless it is InstallAbortedException
+ // and an error occured during abort
+ if (originalException != null) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.InstallHandler_error, (new String[] { this.getLabel() })),
+ originalException);
+ }
+
+ if (newException != null)
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.InstallHandler_error, (new String[] { this.getLabel() })),
+ newException);
+
+ if (abortedException != null) {
+ throw abortedException;
+ }
+
+ }
+ return result;
+ }
+
+ /**
+ * Returns an array of plug-in entries referenced by this feature
+ *
+ * @see IFeature#getPluginEntries()
+ * @since 2.0
+ */
+ public IPluginEntry[] getRawPluginEntries() {
+ PluginEntryModel[] result = getPluginEntryModels();
+ if (result.length == 0)
+ return new IPluginEntry[0];
+ else
+ return (IPluginEntry[]) result;
+ }
+
+ /*
+ * Method filter.
+ * @param result
+ * @return IPluginEntry[]
+ */
+ private IPluginEntry[] filterPluginEntry(IPluginEntry[] all) {
+ List list = new ArrayList();
+ if (all != null) {
+ for (int i = 0; i < all.length; i++) {
+ if (UpdateManagerUtils.isValidEnvironment(all[i]))
+ list.add(all[i]);
+ }
+ }
+
+ IPluginEntry[] result = new IPluginEntry[list.size()];
+ if (!list.isEmpty()) {
+ list.toArray(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the count of referenced plug-in entries.
+ *
+ * @see IFeature#getPluginEntryCount()
+ * @since 2.0
+ */
+ public int getPluginEntryCount() {
+ return getPluginEntries().length;
+ }
+
+ /**
+ * Returns an array of non-plug-in entries referenced by this feature
+ *
+ * @see IFeature#getNonPluginEntries()
+ * @since 2.0
+ */
+ public INonPluginEntry[] getRawNonPluginEntries() {
+ NonPluginEntryModel[] result = getNonPluginEntryModels();
+ if (result.length == 0)
+ return new INonPluginEntry[0];
+ else
+ return (INonPluginEntry[]) result;
+ }
+
+ /**
+ * Returns the count of referenced non-plug-in entries.
+ *
+ * @see IFeature#getNonPluginEntryCount()
+ * @since 2.0
+ */
+ public int getNonPluginEntryCount() {
+ return getNonPluginEntryModels().length;
+ }
+
+ /**
+ * Returns an array of feature references included by this feature
+ *
+ * @return an erray of feature references, or an empty array.
+ * @since 2.0
+ */
+ public IIncludedFeatureReference[] getRawIncludedFeatureReferences()
+ throws CoreException {
+ if (includedFeatureReferences == null)
+ initializeIncludedReferences();
+
+ if (includedFeatureReferences.size() == 0)
+ return new IncludedFeatureReference[0];
+
+ return (IIncludedFeatureReference[]) includedFeatureReferences.toArray(
+ new IIncludedFeatureReference[includedFeatureReferences.size()]);
+ }
+ /**
+ * Returns the download size of the feature, if it can be determined.
+ *
+ * @see IFeature#getDownloadSize()
+ * @since 2.0
+ */
+ public long getDownloadSize() {
+ try {
+ Set allPluginEntries = new HashSet();
+ Set allNonPluginEntries = new HashSet();
+
+ IPluginEntry[] plugins = getPluginEntries();
+ allPluginEntries.addAll(Arrays.asList(plugins));
+ INonPluginEntry[] nonPlugins = getNonPluginEntries();
+ allNonPluginEntries.addAll(Arrays.asList(nonPlugins));
+
+ IFeatureReference[] children = getIncludedFeatureReferences();
+ for (int i = 0; i < children.length; i++) {
+ plugins = children[i].getFeature(null).getPluginEntries();
+ allPluginEntries.addAll(Arrays.asList(plugins));
+ nonPlugins = children[i].getFeature(null).getNonPluginEntries();
+ allNonPluginEntries.addAll(Arrays.asList(nonPlugins));
+ }
+
+ IPluginEntry[] totalPlugins =
+ new IPluginEntry[allPluginEntries.size()];
+ INonPluginEntry[] totalNonPlugins =
+ new INonPluginEntry[allNonPluginEntries.size()];
+ if (allPluginEntries.size() != 0) {
+ allPluginEntries.toArray(totalPlugins);
+ }
+ if (allNonPluginEntries.size() != 0) {
+ allNonPluginEntries.toArray(totalNonPlugins);
+ }
+
+ return getFeatureContentProvider().getDownloadSizeFor(
+ totalPlugins,
+ totalNonPlugins);
+
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ return ContentEntryModel.UNKNOWN_SIZE;
+ }
+ }
+
+ /**
+ * Returns the install size of the feature, if it can be determined.
+ *
+ * @see IFeature#getInstallSize()
+ * @since 2.0
+ */
+ public long getInstallSize() {
+ try {
+ Set allPluginEntries = new HashSet();
+ Set allNonPluginEntries = new HashSet();
+
+ IPluginEntry[] plugins = getPluginEntries();
+ allPluginEntries.addAll(Arrays.asList(plugins));
+ INonPluginEntry[] nonPlugins = getNonPluginEntries();
+ allNonPluginEntries.addAll(Arrays.asList(nonPlugins));
+
+ IFeatureReference[] children = getIncludedFeatureReferences();
+ for (int i = 0; i < children.length; i++) {
+ plugins = children[i].getFeature(null).getPluginEntries();
+ allPluginEntries.addAll(Arrays.asList(plugins));
+ nonPlugins = children[i].getFeature(null).getNonPluginEntries();
+ allNonPluginEntries.addAll(Arrays.asList(nonPlugins));
+ }
+
+ IPluginEntry[] totalPlugins =
+ new IPluginEntry[allPluginEntries.size()];
+ INonPluginEntry[] totalNonPlugins =
+ new INonPluginEntry[allNonPluginEntries.size()];
+ if (allPluginEntries.size() != 0) {
+ allPluginEntries.toArray(totalPlugins);
+ }
+ if (allNonPluginEntries.size() != 0) {
+ allNonPluginEntries.toArray(totalNonPlugins);
+ }
+
+ return getFeatureContentProvider().getInstallSizeFor(
+ totalPlugins,
+ totalNonPlugins);
+
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ return ContentEntryModel.UNKNOWN_SIZE;
+ }
+ }
+
+ /**
+ * Returns the content provider for this feature.
+ *
+ * @see IFeature#getFeatureContentProvider()
+ * @since 2.0
+ */
+ public IFeatureContentProvider getFeatureContentProvider()
+ throws CoreException {
+ if (featureContentProvider == null) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.Feature_NoContentProvider, (new String[] { getVersionedIdentifier().toString() })),
+ null);
+ }
+ return this.featureContentProvider;
+ }
+
+ /**
+ * Returns the content consumer for this feature.
+ *
+ * @see IFeature#getFeatureContentConsumer()
+ * @since 2.0
+ */
+ public IFeatureContentConsumer getFeatureContentConsumer()
+ throws CoreException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Sets the site for this feature.
+ *
+ * @see IFeature#setSite(ISite)
+ * @since 2.0
+ */
+ public void setSite(ISite site) throws CoreException {
+ if (this.site != null) {
+ String featureURLString =
+ (getURL() != null) ? getURL().toExternalForm() : ""; //$NON-NLS-1$
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.Feature_SiteAlreadySet, (new String[] { featureURLString })),
+ null);
+ }
+ this.site = site;
+ }
+
+ /**
+ * Sets the content provider for this feature.
+ *
+ * @see IFeature#setFeatureContentProvider(IFeatureContentProvider)
+ * @since 2.0
+ */
+ public void setFeatureContentProvider(IFeatureContentProvider featureContentProvider) {
+ this.featureContentProvider = featureContentProvider;
+ featureContentProvider.setFeature(this);
+ }
+
+ /**
+ * Return the string representation of this fetaure
+ *
+ * @return feature as string
+ * @since 2.0
+ */
+ public String toString() {
+ String URLString =
+ (getURL() == null)
+ ? Messages.Feature_NoURL
+ : getURL().toExternalForm();
+
+ String verString =
+ NLS.bind(Messages.Feature_FeatureVersionToString, (new String[] { URLString, getVersionedIdentifier().toString() }));
+ String label = getLabel() == null ? "" : getLabel(); //$NON-NLS-1$
+ return verString + " [" + label + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /*
+ * Installation has been cancelled, abort and revert
+ */
+ private void abort() throws CoreException {
+ String msg = Messages.Feature_InstallationCancelled;
+ throw new InstallAbortedException(msg, null);
+ }
+
+ /*
+ * Initializes includes feature references
+ * If the included feature reference is found on the site, add it to the List
+ * Otherwise attempt to instanciate it using the same type as this feature and
+ * using the default location on the site.
+ */
+ private void initializeIncludedReferences() throws CoreException {
+ includedFeatureReferences = new ArrayList();
+
+ IIncludedFeatureReference[] nestedFeatures = getFeatureIncluded();
+ if (nestedFeatures.length == 0)
+ return;
+
+ ISite site = getSite();
+ if (site == null)
+ return;
+
+ for (int i = 0; i < nestedFeatures.length; i++) {
+ IIncludedFeatureReference include = nestedFeatures[i];
+ IIncludedFeatureReference newRef =
+ getPerfectIncludeFeature(site, include);
+ includedFeatureReferences.add(newRef);
+ }
+ }
+
+ /*
+ *
+ */
+ private IIncludedFeatureReference getPerfectIncludeFeature(
+ ISite site,
+ IIncludedFeatureReference include)
+ throws CoreException {
+
+ // [20367] no site, cannot initialize nested references
+ ISiteFeatureReference[] refs = site.getFeatureReferences();
+ VersionedIdentifier identifier = include.getVersionedIdentifier();
+
+ // too long to compute if not a file system
+ // other solution would be to parse feature.xml
+ // when parsing file system to create archive features/FeatureId_Ver.jar
+ if ("file".equals(site.getURL().getProtocol())) { //$NON-NLS-1$
+ // check if declared on the Site
+ if (refs != null) {
+ for (int ref = 0; ref < refs.length; ref++) {
+ if (refs[ref] != null) {
+ VersionedIdentifier id =
+ refs[ref].getVersionedIdentifier();
+ if (identifier.equals(id)) {
+ // found a ISiteFeatureReference that matches our IIncludedFeatureReference
+ IncludedFeatureReference newRef =
+ new IncludedFeatureReference(refs[ref]);
+ newRef.isOptional(include.isOptional());
+ if (include instanceof FeatureReferenceModel)
+ newRef.setLabel(
+ ((FeatureReferenceModel) include)
+ .getLabel());
+ newRef.setSearchLocation(
+ include.getSearchLocation());
+ return newRef;
+ }
+ }
+ }
+ }
+ }
+
+ // instantiate by mapping it based on the site.xml
+ // in future we may ask for a factory to create the feature ref
+ IncludedFeatureReference newRef = new UpdateSiteIncludedFeatureReference(include);
+ newRef.setSite(getSite());
+ IFeatureReference parentRef = getSite().getFeatureReference(this);
+ if (parentRef instanceof FeatureReference) {
+ newRef.setType(((FeatureReference) parentRef).getType());
+ }
+ String featureID = Site.DEFAULT_FEATURE_PATH + identifier.toString();
+ if(this instanceof TargetFeature)
+ featureID = featureID + "/"; //$NON-NLS-1$
+ else
+ featureID = featureID + ".jar"; //$NON-NLS-1$
+ URL featureURL =
+ getSite().getSiteContentProvider().getArchiveReference(featureID);
+ newRef.setURL(featureURL);
+ newRef.setFeatureIdentifier(identifier.getIdentifier());
+ newRef.setFeatureVersion(identifier.getVersion().toString());
+ try {
+ newRef.resolve(getSite().getURL(), null);
+ // no need to get the bundle
+ return newRef;
+ } catch (Exception e) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.Feature_UnableToInitializeFeatureReference, (new String[] { identifier.toString() })),
+ e);
+ }
+ }
+
+ /*
+ *
+ */
+ private void debug(String trace) {
+ //DEBUG
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL) {
+ UpdateCore.debug(trace);
+ }
+ }
+
+ /*
+ *
+ */
+ private void setMonitorTaskName(
+ IProgressMonitor monitor,
+ String taskName) {
+ if (monitor != null)
+ monitor.setTaskName(taskName);
+ }
+
+ /*
+ *
+ */
+ private void monitorWork(IProgressMonitor monitor, int tick)
+ throws CoreException {
+ if (monitor != null) {
+ monitor.worked(tick);
+ if (monitor.isCanceled()) {
+ abort();
+ }
+ }
+ }
+
+ /*
+ *
+ */
+ private void verifyReferences(
+ IVerifier verifier,
+ ContentReference[] references,
+ InstallMonitor monitor,
+ IVerificationListener verificationListener,
+ boolean isFeature)
+ throws CoreException {
+ IVerificationResult vr = null;
+ if (verifier != null) {
+ for (int j = 0; j < references.length; j++) {
+ vr = verifier.verify(this, references[j], isFeature, monitor);
+ if (vr != null) {
+ if (verificationListener == null)
+ return;
+
+ int result = verificationListener.prompt(vr);
+
+ if (result == IVerificationListener.CHOICE_ABORT) {
+ String msg = Messages.JarVerificationService_CancelInstall;
+ Exception e = vr.getVerificationException();
+ throw new InstallAbortedException(msg, e);
+ }
+ if (result == IVerificationListener.CHOICE_ERROR) {
+ throw Utilities
+ .newCoreException(
+ Messages.JarVerificationService_UnsucessfulVerification,
+ vr.getVerificationException());
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * returns reference if the same feature is installed on the site
+ * [18867]
+ */
+ private IFeatureReference featureAlreadyInstalled(ISite targetSite) {
+
+ ISiteFeatureReference[] references = targetSite.getFeatureReferences();
+ IFeatureReference currentReference = null;
+ for (int i = 0; i < references.length; i++) {
+ currentReference = references[i];
+ // do not compare URL
+ try {
+ if (this.equals(currentReference.getFeature(null)))
+ return currentReference; // 18867
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ }
+ }
+
+ UpdateCore.warn(
+ "ValidateAlreadyInstalled:Feature " //$NON-NLS-1$
+ + this
+ + " not found on site:" //$NON-NLS-1$
+ + this.getURL());
+ return null;
+ }
+
+ /*
+ * re initialize children of the feature, invalidate the cache
+ * @param result FeatureReference to reinitialize.
+ */
+ private void reinitializeFeature(IFeatureReference referenceToReinitialize) {
+
+ if (referenceToReinitialize == null)
+ return;
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION)
+ UpdateCore.debug(
+ "Re initialize feature reference:" + referenceToReinitialize); //$NON-NLS-1$
+
+ IFeature feature = null;
+ try {
+ feature = referenceToReinitialize.getFeature(null);
+ if (feature != null && feature instanceof Feature) {
+ ((Feature) feature).initializeIncludedReferences();
+ }
+ // bug 24981 - recursively go into hierarchy
+ // only if site if file
+ ISite site = referenceToReinitialize.getSite();
+ if (site == null)
+ return;
+ URL url = site.getURL();
+ if (url == null)
+ return;
+ if ("file".equals(url.getProtocol())) { //$NON-NLS-1$
+ IFeatureReference[] included =
+ feature.getIncludedFeatureReferences();
+ for (int i = 0; i < included.length; i++) {
+ reinitializeFeature(included[i]);
+ }
+ }
+ } catch (CoreException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * @see org.eclipse.update.core.IFeature#getRawIncludedFeatureReferences()
+ */
+ public IIncludedFeatureReference[] getIncludedFeatureReferences()
+ throws CoreException {
+ return filterFeatures(getRawIncludedFeatureReferences());
+ }
+
+ /*
+ * Method filterFeatures.
+ * Also implemented in Site
+ *
+ * @param list
+ * @return List
+ */
+ private IIncludedFeatureReference[] filterFeatures(IIncludedFeatureReference[] allIncluded) {
+ List list = new ArrayList();
+ if (allIncluded != null) {
+ for (int i = 0; i < allIncluded.length; i++) {
+ IIncludedFeatureReference included = allIncluded[i];
+ if (UpdateManagerUtils.isValidEnvironment(included))
+ list.add(included);
+ else {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_WARNINGS) {
+ UpdateCore.warn(
+ "Filtered out feature reference:" + included); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ IIncludedFeatureReference[] result =
+ new IIncludedFeatureReference[list.size()];
+ if (!list.isEmpty()) {
+ list.toArray(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * @see org.eclipse.update.core.IFeature#getRawNonPluginEntries()
+ */
+ public INonPluginEntry[] getNonPluginEntries() {
+ return filterNonPluginEntry(getRawNonPluginEntries());
+ }
+
+ /**
+ * Method filterPluginEntry.
+ * @param all
+ * @return INonPluginEntry[]
+ */
+ private INonPluginEntry[] filterNonPluginEntry(INonPluginEntry[] all) {
+ List list = new ArrayList();
+ if (all != null) {
+ for (int i = 0; i < all.length; i++) {
+ if (UpdateManagerUtils.isValidEnvironment(all[i]))
+ list.add(all[i]);
+ }
+ }
+
+ INonPluginEntry[] result = new INonPluginEntry[list.size()];
+ if (!list.isEmpty()) {
+ list.toArray(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * @see org.eclipse.update.core.IFeature#getRawPluginEntries()
+ */
+ public IPluginEntry[] getPluginEntries() {
+ return filterPluginEntry(getRawPluginEntries());
+ }
+
+ /**
+ * @see org.eclipse.update.core.IFeature#getImports()
+ */
+ public IImport[] getImports() {
+ return filterImports(getRawImports());
+ }
+
+ /**
+ * Method filterImports.
+ * @param all
+ * @return IImport[]
+ */
+ private IImport[] filterImports(IImport[] all) {
+ List list = new ArrayList();
+ if (all != null) {
+ for (int i = 0; i < all.length; i++) {
+ if (UpdateManagerUtils.isValidEnvironment(all[i]))
+ list.add(all[i]);
+ }
+ }
+
+ IImport[] result = new IImport[list.size()];
+ if (!list.isEmpty()) {
+ list.toArray(result);
+ }
+
+ return result;
+ }
+
+}
\ No newline at end of file
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/FeatureContentProvider.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/FeatureContentProvider.java
new file mode 100644
index 0000000..0ceea5a
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/FeatureContentProvider.java
@@ -0,0 +1,589 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.model.ContentEntryModel;
+import org.eclipse.update.core.model.InstallAbortedException;
+import org.eclipse.update.core.model.NonPluginEntryModel;
+import org.eclipse.update.core.model.PluginEntryModel;
+import org.eclipse.update.internal.core.FatalIOException;
+import org.eclipse.update.internal.core.FeatureDownloadException;
+import org.eclipse.update.internal.core.FileFragment;
+import org.eclipse.update.internal.core.InternalSiteManager;
+import org.eclipse.update.internal.core.LockManager;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+
+/**
+ * Base implementation of a feature content provider. This class provides a set
+ * of helper methods useful for implementing feature content providers. In
+ * particular, methods dealing with downloading and caching of feature files.
+ * <p>
+ * This class must be subclassed 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>
+ * @see org.eclipse.update.core.IFeatureContentProvider
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public abstract class FeatureContentProvider implements IFeatureContentProvider {
+
+ /**
+ *
+ */
+ public class FileFilter {
+
+ private IPath filterPath = null;
+
+ /**
+ * Constructor for FileFilter.
+ */
+ public FileFilter(String filter) {
+ super();
+ this.filterPath = new Path(filter);
+ }
+
+ /**
+ * returns true if the name matches the rule
+ */
+ public boolean accept(String name) {
+
+ if (name == null)
+ return false;
+
+ // no '*' pattern matching
+ // must be equals
+ IPath namePath = new Path(name);
+ if (filterPath.lastSegment().indexOf('*') == -1) {
+ return filterPath.equals(namePath);
+ }
+
+ // check same file extension if extension exists (a.txt/*.txt)
+ // or same file name (a.txt,a.*)
+ String extension = filterPath.getFileExtension();
+ if (extension != null && !extension.equals("*")) { //$NON-NLS-1$
+ if (!extension.equalsIgnoreCase(namePath.getFileExtension()))
+ return false;
+ } else {
+ IPath noExtension = filterPath.removeFileExtension();
+ String fileName = noExtension.lastSegment();
+ if (!fileName.equals("*")) { //$NON-NLS-1$
+ if (!namePath.lastSegment().startsWith(fileName))
+ return false;
+ }
+ }
+
+ // check same path
+ IPath p1 = namePath.removeLastSegments(1);
+ IPath p2 = filterPath.removeLastSegments(1);
+ return p1.equals(p2);
+ }
+
+ }
+
+ private URL base;
+ private IFeature feature;
+ private File tmpDir; // local work area for each provider
+ public static final String JAR_EXTENSION = ".jar"; //$NON-NLS-1$
+
+ private static final String DOT_PERMISSIONS = "permissions.properties"; //$NON-NLS-1$
+ private static final String EXECUTABLES = "permissions.executable"; //$NON-NLS-1$
+
+ /**
+ * Feature content provider constructor
+ *
+ * @param base
+ * feature URL. The interpretation of this URL is specific to
+ * each content provider.
+ * @since 2.0
+ */
+ public FeatureContentProvider(URL base) {
+ this.base = base;
+ this.feature = null;
+ }
+
+ /**
+ * Returns the feature url.
+ *
+ * @see IFeatureContentProvider#getURL()
+ */
+ public URL getURL() {
+ return base;
+ }
+
+ /**
+ * Returns the feature associated with this content provider.
+ *
+ * @see IFeatureContentProvider#getFeature()
+ */
+ public IFeature getFeature() {
+ return feature;
+ }
+
+ /**
+ * Sets the feature associated with this content provider.
+ *
+ * @see IFeatureContentProvider#setFeature(IFeature)
+ */
+ public void setFeature(IFeature feature) {
+ this.feature = feature;
+ }
+
+ /**
+ * Returns the specified reference as a local file system reference. If
+ * required, the file represented by the specified content reference is
+ * first downloaded to the local system
+ *
+ * @param ref
+ * content reference
+ * @param monitor
+ * progress monitor, can be <code>null</code>
+ * @exception IOException
+ * @exception CoreException
+ * @since 2.0
+ */
+ public ContentReference asLocalReference(ContentReference ref, InstallMonitor monitor) throws IOException, CoreException {
+
+ // check to see if this is already a local reference
+ if (ref.isLocalReference())
+ return ref;
+
+ // check to see if we already have a local file for this reference
+ String key = ref.toString();
+
+ // need to synch as another thread my have created the file but
+ // is still copying into it
+ File localFile = null;
+ FileFragment localFileFragment = null;
+ Object keyLock = LockManager.getLock(key);
+ synchronized (keyLock) {
+ localFile = Utilities.lookupLocalFile(key);
+ if (localFile != null) {
+ // check if the cached file is still valid (no newer version on
+ // server)
+ try {
+ if (UpdateManagerUtils.isSameTimestamp(ref.asURL(), localFile.lastModified()))
+ return ref.createContentReference(ref.getIdentifier(), localFile);
+ } catch(FatalIOException e) {
+ throw e;
+ } catch(IOException e) {
+ throw new FeatureDownloadException(NLS.bind(Messages.FeatureContentProvider_ExceptionDownloading, (new Object[] {getURL().toExternalForm()})), e);
+ }
+ }
+
+ if (localFile == null) {
+ localFileFragment = UpdateManagerUtils.lookupLocalFileFragment(key);
+ }
+ //
+ // download the referenced file into local temporary area
+ InputStream is = null;
+ OutputStream os = null;
+ long bytesCopied = 0;
+ long inputLength = 0;
+ boolean success = false;
+ if (monitor != null) {
+ monitor.saveState();
+ monitor.setTaskName(Messages.FeatureContentProvider_Downloading);
+ monitor.subTask(ref.getIdentifier() + " "); //$NON-NLS-1$
+ try {
+ monitor.setTotalCount(ref.getInputSize());
+ } catch (FatalIOException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new FeatureDownloadException(NLS.bind(Messages.FeatureContentProvider_ExceptionDownloading, (new Object[] {getURL().toExternalForm()})), e);
+ }
+ monitor.showCopyDetails(true);
+ }
+
+ try {
+ //long startTime = System.nanoTime();
+ if (localFileFragment != null && "http".equals(ref.asURL().getProtocol())) { //$NON-NLS-1$
+ localFile = localFileFragment.getFile();
+ try {
+ // get partial input stream
+ is = ref.getPartialInputStream(localFileFragment.getSize());
+ inputLength = ref.getInputSize() - localFileFragment.getSize();
+ // get output stream to append to file fragment
+ os = new BufferedOutputStream(
+ // PAL foundation
+ //new FileOutputStream(localFile, true));
+ new FileOutputStream(localFile.getPath(), true));
+ } catch (FatalIOException e) {
+ throw e;
+ } catch (IOException e) {
+ try {
+ if (is != null)
+ is.close();
+ } catch (IOException ioe) {
+ }
+ is = null;
+ os = null;
+ localFileFragment = null;
+ throw new FeatureDownloadException(NLS.bind(Messages.FeatureContentProvider_ExceptionDownloading, (new Object[] {getURL().toExternalForm()})), e);
+ }
+ }
+ if (is == null) {
+ // must download from scratch
+ localFile = Utilities.createLocalFile(getWorkingDirectory(), null);
+ try {
+ is = ref.getInputStream();
+ inputLength = ref.getInputSize();
+ } catch (FatalIOException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.FeatureContentProvider_UnableToRetrieve, (new Object[] {ref})), e);
+ } catch (IOException e) {
+ throw new FeatureDownloadException(NLS.bind(Messages.FeatureContentProvider_ExceptionDownloading, (new Object[] {getURL().toExternalForm()})), e);
+ }
+
+ try {
+ os = new BufferedOutputStream(new FileOutputStream(localFile));
+ } catch (FileNotFoundException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.FeatureContentProvider_UnableToCreate, (new Object[] {localFile})), e);
+ }
+ }
+
+ Date start = new Date();
+ if (localFileFragment != null) {
+ bytesCopied = localFileFragment.getSize();
+ if (monitor != null) {
+ monitor.setCopyCount(bytesCopied);
+ }
+ }
+
+ // Transfer as many bytes as possible from input to output stream
+ long offset = UpdateManagerUtils.copy(is, os, monitor, inputLength);
+ if (offset != -1) {
+ bytesCopied += offset;
+ if (bytesCopied > 0) {
+ // preserve partially downloaded file
+ UpdateManagerUtils.mapLocalFileFragment(key, new FileFragment(localFile, bytesCopied));
+ }
+ if (monitor != null && monitor.isCanceled()) {
+ String msg = Messages.Feature_InstallationCancelled;
+ throw new InstallAbortedException(msg, null);
+ } else {
+ throw new FeatureDownloadException(NLS.bind(Messages.FeatureContentProvider_ExceptionDownloading, (new Object[] {getURL().toExternalForm()})), new IOException());
+ }
+ } else {
+ UpdateManagerUtils.unMapLocalFileFragment(key);
+ }
+
+ Date stop = new Date();
+ long timeInseconds = (stop.getTime() - start.getTime()) / 1000;
+ // time in milliseconds /1000 = time in seconds
+ InternalSiteManager.downloaded(
+ ref.getInputSize(),
+ (timeInseconds),
+ ref.asURL());
+
+ success = true;
+ //long endTime = System.nanoTime();
+ // file is downloaded succesfully, map it
+ Utilities.mapLocalFile(key, localFile);
+
+ /*if (ref.asURL().toExternalForm().endsWith("jar")) {
+ synchronized(this.getClass()) {
+ timer += (endTime - startTime);
+ if (first == 0) {
+ first = endTime - startTime;
+ }
+ }
+ }*/
+ } catch (ClassCastException e) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.FeatureContentProvider_UnableToCreate, (new Object[] { localFile })),
+ e);
+ } finally {
+ //Do not close IS if user cancel,
+ //closing IS will read the entire Stream until the end
+ if (success && is != null)
+ try {
+ is.close();
+ } catch (IOException e) {
+ }
+ if (os != null)
+ try {
+ os.close(); // should flush buffer stream
+ } catch (IOException e) {
+ }
+
+ if (success || bytesCopied > 0) {
+ // set the timestamp on the temp file to match the remote
+ // timestamp
+ localFile.setLastModified(ref.getLastModified());
+ }
+ if (monitor != null)
+ monitor.restoreState();
+ }
+ LockManager.returnLock(key);
+ } // end lock
+ ContentReference reference =
+ ref.createContentReference(ref.getIdentifier(), localFile);
+
+ UpdateCore.getPlugin().getUpdateSession().markVisited(ref.asURL());
+
+ return reference;
+ }
+
+ /**
+ * Returns the specified reference as a local file. If required, the file
+ * represented by the specified content reference is first downloaded to
+ * the local system
+ *
+ * @param ref
+ * content reference
+ * @param monitor
+ * progress monitor, can be <code>null</code>
+ * @exception IOException
+ * @exception CoreException
+ * @since 2.0
+ */
+ public File asLocalFile(ContentReference ref, InstallMonitor monitor) throws IOException, CoreException {
+ File file = ref.asFile();
+ ContentReference localRef = asLocalReference(ref, monitor);
+ file = localRef.asFile();
+ return file;
+ }
+
+ /**
+ * Returns working directory for this content provider
+ *
+ * @return working directory
+ * @exception IOException
+ * @since 2.0
+ */
+ protected File getWorkingDirectory() throws IOException {
+ if (tmpDir == null)
+ tmpDir = Utilities.createWorkingDirectory();
+ return tmpDir;
+ }
+
+ /**
+ * Returns the total size of all archives required for the specified
+ * plug-in and non-plug-in entries (the "packaging" view).
+ *
+ * @see IFeatureContentProvider#getDownloadSizeFor(IPluginEntry[],
+ * INonPluginEntry[])
+ */
+ public long getDownloadSizeFor(IPluginEntry[] pluginEntries, INonPluginEntry[] nonPluginEntries) {
+ long result = 0;
+
+ // if both are null or empty, return UNKNOWN size
+ if ((pluginEntries == null || pluginEntries.length == 0) && (nonPluginEntries == null || nonPluginEntries.length == 0)) {
+ return ContentEntryModel.UNKNOWN_SIZE;
+ }
+
+ // loop on plugin entries
+ long size = 0;
+ if (pluginEntries != null)
+ for (int i = 0; i < pluginEntries.length; i++) {
+ size = ((PluginEntryModel) pluginEntries[i]).getDownloadSize();
+ if (size == ContentEntryModel.UNKNOWN_SIZE) {
+ return ContentEntryModel.UNKNOWN_SIZE;
+ }
+ result += size;
+ }
+
+ // loop on non plugin entries
+ if (nonPluginEntries != null)
+ for (int i = 0; i < nonPluginEntries.length; i++) {
+ size = ((NonPluginEntryModel) nonPluginEntries[i]).getDownloadSize();
+ if (size == ContentEntryModel.UNKNOWN_SIZE) {
+ return ContentEntryModel.UNKNOWN_SIZE;
+ }
+ result += size;
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the total size of all files required for the specified plug-in
+ * and non-plug-in entries (the "logical" view).
+ *
+ * @see IFeatureContentProvider#getInstallSizeFor(IPluginEntry[],
+ * INonPluginEntry[])
+ */
+ public long getInstallSizeFor(IPluginEntry[] pluginEntries, INonPluginEntry[] nonPluginEntries) {
+ long result = 0;
+
+ // if both are null or empty, return UNKNOWN size
+ if ((pluginEntries == null || pluginEntries.length == 0) && (nonPluginEntries == null || nonPluginEntries.length == 0)) {
+ return ContentEntryModel.UNKNOWN_SIZE;
+ }
+
+ // loop on plugin entries
+ long size = 0;
+ if (pluginEntries != null)
+ for (int i = 0; i < pluginEntries.length; i++) {
+ size = ((PluginEntryModel) pluginEntries[i]).getInstallSize();
+ if (size == ContentEntryModel.UNKNOWN_SIZE) {
+ return ContentEntryModel.UNKNOWN_SIZE;
+ }
+ result += size;
+ }
+
+ // loop on non plugin entries
+ if (nonPluginEntries != null)
+ for (int i = 0; i < nonPluginEntries.length; i++) {
+ size = ((NonPluginEntryModel) nonPluginEntries[i]).getInstallSize();
+ if (size == ContentEntryModel.UNKNOWN_SIZE) {
+ return ContentEntryModel.UNKNOWN_SIZE;
+ }
+ result += size;
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the path identifier for a plugin entry. <code>plugins/<pluginId>_<pluginVersion>.jar</code>
+ *
+ * @return the path identifier
+ */
+ protected String getPathID(IPluginEntry entry) {
+ return Site.DEFAULT_PLUGIN_PATH + entry.getVersionedIdentifier().toString() + JAR_EXTENSION;
+ }
+
+ /**
+ * Returns the path identifer for a non plugin entry. <code>features/<featureId>_<featureVersion>/<dataId></code>
+ *
+ * @return the path identifier
+ */
+ protected String getPathID(INonPluginEntry entry) {
+ String nonPluginBaseID = Site.DEFAULT_FEATURE_PATH + feature.getVersionedIdentifier().toString() + "/"; //$NON-NLS-1$
+ return nonPluginBaseID + entry.getIdentifier();
+ }
+
+ /**
+ * Sets the permission of all the ContentReferences Check for the
+ * .permissions contentReference and use it to set the permissions of other
+ * ContentReference
+ */
+ protected void validatePermissions(ContentReference[] references) {
+
+ if (references == null || references.length == 0)
+ return;
+
+ Map permissions = getPermissions(references);
+ if (permissions.isEmpty())
+ return;
+
+ for (int i = 0; i < references.length; i++) {
+ ContentReference contentReference = references[i];
+ String id = contentReference.getIdentifier();
+ Object value = null;
+ if ((value = matchesOneRule(id, permissions)) != null) {
+ Integer permission = (Integer) value;
+ contentReference.setPermission(permission.intValue());
+ }
+ }
+ }
+
+ /**
+ * Returns the value of the matching rule or <code>null</code> if none
+ * found. A rule is matched if the id is equals to a key, or if the id is
+ * resolved by a key. if the id is <code>/path/file.txt</code> it is
+ * resolved by <code>/path/*</code> or <code>/path/*.txt</code>
+ *
+ * @param id
+ * the identifier
+ * @param permissions
+ * list of rules
+ * @return Object the value of the matching rule or <code>null</code>
+ */
+ private Object matchesOneRule(String id, Map permissions) {
+
+ Set keySet = permissions.keySet();
+ Iterator iter = keySet.iterator();
+ while (iter.hasNext()) {
+ FileFilter rule = (FileFilter) iter.next();
+ if (rule.accept(id)) {
+ return permissions.get(rule);
+ }
+ }
+
+ return null;
+ }
+
+ /*
+ * returns the permission MAP
+ */
+ private Map getPermissions(ContentReference[] references) {
+
+ Map result = new HashMap();
+ // search for .permissions
+ boolean notfound = true;
+ ContentReference permissionReference = null;
+ for (int i = 0; i < references.length && notfound; i++) {
+ ContentReference contentReference = references[i];
+ if (DOT_PERMISSIONS.equals(contentReference.getIdentifier())) {
+ notfound = false;
+ permissionReference = contentReference;
+ }
+ }
+ if (notfound)
+ return result;
+
+ Properties prop = new Properties();
+ InputStream propertyStream = null;
+ try {
+ try {
+ propertyStream = permissionReference.getInputStream();
+ prop.load(propertyStream);
+ } finally {
+ if (propertyStream != null)
+ propertyStream.close();
+ }
+ } catch (IOException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+
+ String executables = prop.getProperty(EXECUTABLES);
+ if (executables == null)
+ return result;
+
+ StringTokenizer tokenizer = new StringTokenizer(executables, ","); //$NON-NLS-1$
+ Integer defaultExecutablePermission = new Integer(ContentReference.DEFAULT_EXECUTABLE_PERMISSION);
+ while (tokenizer.hasMoreTokens()) {
+ FileFilter filter = new FileFilter(tokenizer.nextToken());
+ result.put(filter, defaultExecutablePermission);
+ }
+
+ return result;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/FeatureReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/FeatureReference.java
new file mode 100644
index 0000000..520081c
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/FeatureReference.java
@@ -0,0 +1,296 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.model.FeatureReferenceModel;
+import org.eclipse.update.core.model.SiteModel;
+import org.eclipse.update.internal.core.FeatureTypeFactory;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+
+/**
+ * Convenience implementation of a feature reference.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.IFeatureReference
+ * @see org.eclipse.update.core.model.FeatureReferenceModel
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class FeatureReference extends FeatureReferenceModel implements IFeatureReference, IPlatformEnvironment {
+
+ private VersionedIdentifier versionId;
+
+ //PERF: new instance variable
+ private IFeature exactFeature;
+
+ /**
+ * Feature reference default constructor
+ */
+ public FeatureReference() {
+ super();
+ }
+
+ /**
+ * Constructor FeatureReference.
+ * @param ref the reference to copy
+ */
+ public FeatureReference(IFeatureReference ref) {
+ super((FeatureReferenceModel) ref);
+ try {
+ setURL(ref.getURL());
+ } catch (CoreException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Constructor FeatureReference.
+ * @param ref the reference to copy
+ */
+ public FeatureReference(FeatureReferenceModel ref) {
+ super(ref);
+ try {
+ setURL(ref.getURL());
+ } catch (CoreException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the feature this reference points to
+ * @return the feature on the Site
+ * @deprecated use getFeaure(IProgressMonitor)
+ */
+ public IFeature getFeature() throws CoreException {
+ return getFeature(null);
+ }
+
+ /**
+ * Returns the feature this reference points to
+ * @return the feature on the Site
+ */
+ public IFeature getFeature(IProgressMonitor monitor) throws CoreException {
+
+ if (exactFeature != null)
+ return exactFeature;
+ exactFeature = getFeature(this,monitor);
+ return exactFeature;
+ }
+
+ /**
+ * Returns the feature the reference points to
+ * @param ref the feature reference
+ * @return the feature on the Site
+ */
+ protected IFeature getFeature(IFeatureReference ref,IProgressMonitor monitor) throws CoreException {
+
+ IFeature feature = null;
+ URL refURL = ref.getURL();
+ feature = createFeature(refURL,monitor);
+ return feature;
+ }
+
+ /*
+ * create an instance of a concrete feature corresponding to this reference
+ */
+ private IFeature createFeature(URL url,IProgressMonitor monitor) throws CoreException {
+ String type = getType();
+ ISite site = getSite();
+ // if the site exists, use the site factory
+ if (site != null) {
+ return site.createFeature(type, url, monitor);
+ }
+
+ IFeatureFactory factory = FeatureTypeFactory.getInstance().getFactory(type);
+ return factory.createFeature(url, site, monitor);
+ }
+
+ /**
+ * Returns the update site for the referenced feature
+ *
+ * @see IFeatureReference#getSite()
+ * @since 2.0
+ */
+ public ISite getSite() {
+ return (ISite) getSiteModel();
+ }
+
+ /**
+ * Sets the feature reference URL.
+ * This is typically performed as part of the feature reference creation
+ * operation. Once set, the url should not be reset.
+ *
+ * @see IFeatureReference#setURL(URL)
+ * @since 2.0
+ */
+ public void setURL(URL url) throws CoreException {
+ if (url != null) {
+ setURLString(url.toExternalForm());
+ try {
+ resolve(url, null);
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.FeatureReference_UnableToResolveURL, (new String[] { url.toExternalForm() })), e);
+ }
+ }
+ }
+
+ /**
+ * Associates a site with the feature reference.
+ * This is typically performed as part of the feature reference creation
+ * operation. Once set, the site should not be reset.
+ *
+ * @see IFeatureReference#setSite(ISite)
+ * @since 2.0
+ */
+ public void setSite(ISite site) {
+ setSiteModel((SiteModel) site);
+ }
+
+ /**
+ * Returns the feature identifier.
+ *
+ * @see IFeatureReference#getVersionedIdentifier()
+ * @since 2.0
+ */
+ public VersionedIdentifier getVersionedIdentifier() {
+
+ if (versionId != null)
+ return versionId;
+
+ String id = getFeatureIdentifier();
+ String ver = getFeatureVersion();
+ if (id != null && ver != null) {
+ try {
+ versionId = new VersionedIdentifier(id, ver);
+ return versionId;
+ } catch (Exception e) {
+ UpdateCore.warn("Unable to create versioned identifier:" + id + ":" + ver); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ // we need the exact match or we may have an infinite loop
+ versionId = new VersionedIdentifier(getURL().toExternalForm(), null);
+ try {
+ versionId = getFeature(null).getVersionedIdentifier();
+ } catch (CoreException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+ return versionId;
+ }
+
+ /**
+ * @see org.eclipse.update.core.IFeatureReference#getName()
+ */
+ public String getName() {
+ if (super.getLabel() != null)
+ return super.getLabel();
+ try {
+ return getFeature(null).getLabel();
+ } catch (CoreException e) {
+ return getVersionedIdentifier().toString();
+ }
+ }
+
+ /**
+ * Get optional operating system specification as a comma-separated string.
+ *
+ * @return the operating system specification string, or <code>null</code>.
+ * @since 2.1
+ */
+ public String getOS() {
+ if (super.getOS() == null && getURL()!=null)
+ try {
+ return getFeature(null).getOS();
+ } catch (CoreException e) {
+ return null;
+ }
+ return super.getOS();
+ }
+
+ /**
+ * Get optional windowing system specification as a comma-separated string.
+ *
+ * @return the windowing system specification string, or <code>null</code>.
+ * @since 2.1
+ */
+ public String getWS() {
+ if (super.getWS() == null && getURL()!=null)
+ try {
+ return getFeature(null).getWS();
+ } catch (CoreException e) {
+ return null;
+ }
+ return super.getWS();
+ }
+
+ /**
+ * Get optional system architecture specification as a comma-separated string.
+ *
+ * @return the system architecture specification string, or <code>null</code>.
+ * @since 2.1
+ */
+ public String getOSArch() {
+ if (super.getOSArch() == null && getURL()!=null)
+ try {
+ return getFeature(null).getOSArch();
+ } catch (CoreException e) {
+ return null;
+ }
+ return super.getOSArch();
+ }
+
+ /**
+ * Get optional locale specification as a comma-separated string.
+ *
+ * @return the locale specification string, or <code>null</code>.
+ * @since 2.1
+ */
+ public String getNL() {
+ if (super.getNL() == null && getURL()!=null)
+ try {
+ return getFeature(null).getNL();
+ } catch (CoreException e) {
+ return null;
+ }
+ return super.getNL();
+ }
+
+ /**
+ * Returns <code>true</code> if this feature is patching another feature,
+ * <code>false</code> otherwise
+ * @return boolean
+ */
+ public boolean isPatch() {
+ if (super.getPatch() == null)
+ try {
+ return getFeature(null).isPatch();
+ } catch (CoreException e) {
+ return false;
+ }
+ return "true".equalsIgnoreCase(super.getPatch()); //$NON-NLS-1$
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IArchiveReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IArchiveReference.java
new file mode 100644
index 0000000..776226c
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IArchiveReference.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * Site archive interface.
+ * Site archive is a representation of a packaged archive (file) located
+ * on an update site. It allows a "symbolic" path used to identify
+ * a plug-in or non-plug-in feature entry to be explicitly mapped
+ * to a specific URL.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.ArchiveReference
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IArchiveReference extends IAdaptable {
+
+ /**
+ *
+ * @return the archive "symbolic" path, or <code>null</code>
+ * @since 2.0
+ */
+ public String getPath();
+
+ /**
+ * Retrieve the site archive URL
+ *
+ * @return the archive URL, or <code>null</code>
+ * @since 2.0
+ */
+ public URL getURL();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/ICategory.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/ICategory.java
new file mode 100644
index 0000000..c3ac959
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/ICategory.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * Feature category definition.
+ * A site can organize its features into categories. Categories
+ * can be further organized into hierarchies. Each category name
+ * is a composed of the name of its parent and a simple identifier
+ * separated by a slash ("/"). For example <code>tools/utilities/print</code>
+ * defines a category that is a child of <code>tools/utilities</code> and
+ * grandchild of <code>tools</code>.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.Category
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface ICategory extends IAdaptable{
+
+ /**
+ * Retrieve the name of the category. The name can be a simple
+ * token (root category) or a number of slash-separated ("/")
+ * tokens.
+ *
+ * @return the category name
+ * @since 2.0
+ */
+ public String getName();
+
+ /**
+ * Retrieve the displayable label for the category
+ *
+ * @return displayable category label, or <code>null</code>
+ * @since 2.0
+ */
+ public String getLabel();
+
+ /**
+ * Retrieve the detailed category description
+ *
+ * @return category description, or <code>null</code>
+ * @since 2.0
+ */
+ public IURLEntry getDescription();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IContentConsumer.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IContentConsumer.java
new file mode 100644
index 0000000..74fc952
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IContentConsumer.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Generic content consumer.
+ * A generic content consumer is used to store plug-in and non-plug-in files
+ * for a feature.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients
+ * will only use the content consumer provided by the feature type(s)
+ * implemented by the platform.
+ * </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>
+ * @see org.eclipse.update.core.IFeatureContentConsumer
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IContentConsumer {
+
+ /**
+ * Stores a file.
+ *
+ * @see IFeatureContentConsumer#open(IPluginEntry)
+ * @see IFeatureContentConsumer#open(INonPluginEntry)
+ * @param contentReference reference to the file to store
+ * @param monitor progress monitor, can be <code>null</code>
+ * @exception CoreException
+ * @since 2.0
+ */
+ public void store(ContentReference contentReference, IProgressMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Indicates successful completion of the store operations for this
+ * consumer
+ *
+ * @exception CoreException
+ * @since 2.0
+ */
+ public void close() throws CoreException;
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeature.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeature.java
new file mode 100644
index 0000000..8af1af9
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeature.java
@@ -0,0 +1,483 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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.update.core;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.update.core.model.InstallAbortedException;
+
+/**
+ * Feature defines the packaging "container" for a group of related plug-ins,
+ * plug-in fragments, and optionally non-plug-in files.
+ * <p>
+ * Features are treated purely as an installation and packaging construct.
+ * They do not play a role during Eclipse plug-in execution.
+ * They are simply an inclusive "manifest" of the plug-ins, fragments
+ * and other files that make up that feature. If features are logically made
+ * up of plug-ins from "sub-features", the top-level feature "manifest"
+ * must be fully resolved at packaging time.
+ * </p>
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.Feature
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IFeature extends IAdaptable, IPlatformEnvironment {
+
+ /**
+ * Indicates a 'happy' feature
+ * A feature is considered to be 'happy' in the context of a local site
+ * if all the plug-ins referenced by the feature are installed on the site and no other
+ * version of any of the plug-ins are installed on any other site of the local site.
+ *
+ * @see org.eclipse.update.configuration.IConfiguredSite#getBrokenStatus(IFeature)
+ * @since 2.0
+ */
+ public static final int STATUS_HAPPY = 0;
+
+ /**
+ * Indicates a 'happy' feature
+ * A feature is considered to be 'ambiguous' in the context of a local site
+ * if all the plug-ins referenced by the feature are installed on the site and other
+ * version of any of the plug-ins are installed on any other site of the local site.
+ *
+ * @see org.eclipse.update.configuration.IConfiguredSite#getBrokenStatus(IFeature)
+ */
+ public static final int STATUS_AMBIGUOUS = 1;
+
+ /**
+ * Indicates an 'unhappy' feature
+ * A feature is considered to be 'unhappy' in the context of this site,
+ * if some of the plug-ins referenced by the feature are not installed on this site.
+ *
+ * @see org.eclipse.update.configuration.IConfiguredSite#getBrokenStatus(IFeature)
+ * @since 2.0
+ */
+ public static final int STATUS_UNHAPPY = 2;
+
+
+ /**
+ * Indicates a disable feature
+ *
+ * @see org.eclipse.update.configuration.IConfiguredSite#getBrokenStatus(IFeature)
+ * @since 2.0.2
+ */
+ public static final int STATUS_DISABLED = -1;
+
+ /**
+ * Indicates the one-click update will search the
+ * location of the nesting root feature.
+ *
+ * @since 2.0.1
+ */
+ public static final int SEARCH_LOCATION_DEFAULT = 0;
+
+ /**
+ * Indicates the one-click update will search the
+ * location defined by the feature.
+ *
+ * @since 2.0.1
+ */
+ public static final int SEARCH_LOCATION_FEATURE = 1;
+
+ /**
+ * Indicates the one-click update will search both the
+ * location of the nesting root feature and the
+ * location defined by the feature.
+ *
+ * @since 2.0.1
+ */
+ public static final int SEARCH_LOCATION_BOTH = 2;
+
+
+ /**
+ * Returns the feature identifier.
+ *
+ * @return the feature identifier.
+ * @since 2.0
+ */
+ public VersionedIdentifier getVersionedIdentifier();
+
+ /**
+ * Returns the site this feature is associated with.
+ *
+ * @return the site for this feature
+ * @since 2.0
+ */
+ public ISite getSite();
+
+ /**
+ * Returns the displayable label of the feature.
+ *
+ * @return feature label, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getLabel();
+
+ /**
+ * Returns the feature URL.
+ * This is the URL that was used to create the feature. The interpretation
+ * of the URL is dependent on the concrete feature implementation. *
+ * @return feature URL
+ * @since 2.0
+ */
+ public URL getURL();
+
+ /**
+ * Returns an information entry referencing the location of the
+ * feature update site. The update site can be accessed to obtain
+ * feature updates for this feature.
+ *
+ * @return update site entry, or <code>null</code>.
+ * @since 2.0
+ */
+ public IURLEntry getUpdateSiteEntry();
+
+ /**
+ * Return an array of information entries referencing locations of other
+ * update sites. This mechanism can be used by features to distribute
+ * location information about general update sites to clients.
+ *
+ * @return an array of site entries, or an empty array.
+ * @since 2.0
+ */
+ public IURLEntry[] getDiscoverySiteEntries();
+
+ /**
+ * Returns a displayable label identifying the provider of this feature
+ *
+ * @return provider label, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getProvider();
+
+ /**
+ * Returns and optional custom install handler entry.
+ *
+ * @return install handler entry, or <code>null</code> if
+ * none was specified
+ * @since 2.0
+ */
+ public IInstallHandlerEntry getInstallHandlerEntry();
+
+ /**
+ * Returns the feature description.
+ *
+ * @return feature description, or <code>null</code>.
+ * @since 2.0
+ */
+ public IURLEntry getDescription();
+
+ /**
+ * Returns the copyright information for the feature.
+ *
+ * @return copyright information, or <code>null</code>.
+ * @since 2.0
+ */
+ public IURLEntry getCopyright();
+
+ /**
+ * Returns the license information for the feature.
+ *
+ * @return feature license, or <code>null</code>.
+ * @since 2.0
+ */
+ public IURLEntry getLicense();
+
+ /**
+ * Return optional image for the feature.
+ *
+ * @return the URL pointing to the image, , or <code>null</code>.
+ * @since 2.0
+ */
+ public URL getImage();
+
+ /**
+ * Return a list of plug-in dependencies for this feature. A plug-in
+ * dependency is a reference to a plug-in required for feature execution
+ * that is not packaged as part of the feature.
+ * filtered by the operating system, windowing system and architecture system
+ * set in <code>SiteManager</code>
+ *
+ * @return the list of required plug-in dependencies, or an empty array.
+ * @since 2.0
+ */
+ public IImport[] getImports();
+
+ /**
+ * Return a list of plug-in dependencies for this feature. A plug-in
+ * dependency is a reference to a plug-in required for feature execution
+ * that is not packaged as part of the feature.
+ * No filtering occurs
+ *
+ * @return the list of required plug-in dependencies, or an empty array.
+ * @since 2.1
+ */
+ public IImport[] getRawImports();
+
+ /**
+ * Return the identifier of the primary plugin associated to this feature
+ * or <code>null</code> if the feature is not a primary feature.
+ * If the primary plugin id is not specified and the feature is a primary
+ * feature, returns the feature identifier.
+ *
+ * @return the identifier of the associated primary plugin or <code>null</code>
+ * @since 2.1
+ */
+ public String getPrimaryPluginID();
+
+
+ /**
+ * Install the contents of this feature into the specified target feature.
+ * All optional features will be installed
+ *
+ * @param targetFeature
+ * @param verificationListener
+ * @param monitor
+ * @exception InstallAbortedException when the user cancels the install
+ * @exception CoreException
+ * @since 2.0
+ */
+ public IFeatureReference install(
+ IFeature targetFeature,
+ IVerificationListener verificationListener,
+ IProgressMonitor monitor)
+ throws InstallAbortedException,CoreException;
+
+ /**
+ * Install the contents of this feature into the specified target feature.
+ * Only the listed optional features will be installed.
+ *
+ * @param targetFeature
+ * @param optionalFeatures the optional features to be installed
+ * @param verificationListener
+ * @param monitor
+ * @exception InstallAbortedException when the user cancels the install
+ * @exception CoreException
+ * @since 2.0.1
+ */
+ public IFeatureReference install(
+ IFeature targetFeature,
+ IFeatureReference[] optionalFeatures,
+ IVerificationListener verificationListener,
+ IProgressMonitor monitor)
+ throws InstallAbortedException,CoreException;
+
+ /**
+ * Returns an array of feature references included by this feature
+ * filtered by the operating system, windowing system and architecture system
+ * set in <code>SiteManager</code>
+ *
+ * @return an array of feature references, or an empty array.
+ * @since 2.0
+ */
+ public IIncludedFeatureReference[] getIncludedFeatureReferences() throws CoreException;
+
+ /**
+ * Returns an array of feature references included by this feature
+ * No filtering occurs
+ *
+ * @return an array of feature references, or an empty array.
+ * @since 2.0
+ */
+ public IIncludedFeatureReference[] getRawIncludedFeatureReferences() throws CoreException;
+
+ /**
+ * Returns an array of plug-in entries referenced by this feature
+ * filtered by the operating system, windowing system and architecture system
+ * set in <code>SiteManager</code>
+ *
+ * @return an array of plug-in entries, or an empty array.
+ * @since 2.0
+ */
+ public IPluginEntry[] getPluginEntries();
+
+ /**
+ * Returns an array of plug-in entries referenced by this feature
+ * No filtering occurs
+ *
+ * @return an array of plug-in entries, or an empty array.
+ * @since 2.1
+ */
+ public IPluginEntry[] getRawPluginEntries();
+
+ /**
+ * Returns the count of referenced plug-in entries.
+ *
+ * @return plug-in entry count
+ * @since 2.0
+ */
+ public int getPluginEntryCount();
+
+ /**
+ * Returns an array of non-plug-in entries referenced by this feature
+ * filtered by the operating system, windowing system and architecture system
+ * set in <code>SiteManager</code>
+ *
+ * @return an array of non-plug-in entries, or an empty array.
+ * @since 2.0
+ */
+ public INonPluginEntry[] getNonPluginEntries();
+
+ /**
+ * Returns an array of non-plug-in entries referenced by this feature
+ * No filtering occurs
+ *
+ * @return an array of non-plug-in entries, or an empty array.
+ * @since 2.1
+ */
+ public INonPluginEntry[] getRawNonPluginEntries();
+
+ /**
+ * Returns the count of referenced non-plug-in entries.
+ *
+ * @return non-plug-in entry count
+ * @since 2.0
+ */
+ public int getNonPluginEntryCount();
+
+ /**
+ * Returns the download size of the feature, if it can be determined.
+ *
+ * @see org.eclipse.update.core.model.ContentEntryModel#UNKNOWN_SIZE
+ * @return download size of the feature in KiloBytes, or an indication
+ * the size could not be determined
+ * @since 2.0
+ */
+ public long getDownloadSize();
+
+ /**
+ * Returns the install size of the feature, if it can be determined.
+ *
+ * @see org.eclipse.update.core.model.ContentEntryModel#UNKNOWN_SIZE
+ * @return install size of the feature in KiloBytes, or an indication
+ * the size could not be determined
+ * @since 2.0
+ */
+ public long getInstallSize();
+
+ /**
+ * Indicates whether the feature can be used as a primary feature.
+ *
+ * @return <code>true</code> if this is a primary feature,
+ * otherwise <code>false</code>
+ * @since 2.0
+ */
+ public boolean isPrimary();
+
+ /**
+ * Indicates whether the feature must be processed alone during installation
+ * and configuration. Features that are not exclusive can be installed in a
+ * batch.
+ *
+ * @return <code>true</code> if feature requires exclusive processing,
+ * <code>false</code> otherwise.
+ * @since 2.1
+ */
+ public boolean isExclusive();
+
+ /**
+ * Returns an optional identifier of an application to be used when
+ * starting up the platform with this feature as the primary feature.
+ * The application identifier must represent a valid application registered
+ * in the <code>org.eclipse.core.runtime.applications</code> extension point.
+ *
+ * @return application identifier, or <code>null</code>
+ * @since 2.0
+ */
+ public String getApplication();
+
+ /**
+ * Returns an optional identifier of a co-location affinity feature.
+ *
+ * @return feature identifier, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getAffinityFeature();
+
+ /**
+ * Returns the content provider for this feature. A content provider
+ * is an abstraction of each feature internal packaging structure.
+ * It allows the feature content to be accessed in a standard way
+ * regardless of the internal packaging. All concrete features
+ * need to be able to return a content provider.
+ *
+ * @return feature content provider
+ * @exception CoreException
+ * @since 2.0
+ */
+ public IFeatureContentProvider getFeatureContentProvider()
+ throws CoreException;
+
+ /**
+ * Returns the content consumer for this feature. A content consumer
+ * is an abstraction of each feature internal packaging mechanism.
+ * It allows content to be stored into a feature in a standard way
+ * regardless of the packaging mechanism used. Only concrete features
+ * that support storing need to implement a content consumer. The platform
+ * implements at least one feature type supporting content consumer.
+ * This is the feature type representing a locally-installed
+ * feature.
+ *
+ * @return feature content consumer
+ * @exception CoreException
+ * @exception UnsupportedOperationException
+ * @since 2.0
+ */
+ public IFeatureContentConsumer getFeatureContentConsumer()
+ throws CoreException;
+
+ /**
+ * Sets the site for this feature. This is typically performed as part
+ * of the feature creation operation. Once set, the site
+ * should not be reset.
+ *
+ * @param site the site
+ * @throws CoreException site for this feature is already set
+ * @since 2.0
+ */
+ public void setSite(ISite site) throws CoreException;
+
+ /**
+ * Sets the content provider for this feature. This is typically
+ * performed as part of the feature creation operation. Once set, the
+ * provider should not be reset.
+ *
+ * @param featureContentProvider content provider
+ * @since 2.0
+ */
+ public void setFeatureContentProvider(IFeatureContentProvider featureContentProvider);
+
+ /**
+ * Returns <code>true</code> if this feature is patching another feature,
+ * <code>false</code> otherwise
+ * @return boolean
+ * @since 2.1
+ */
+ public boolean isPatch();
+
+
+}
\ No newline at end of file
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeatureContentConsumer.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeatureContentConsumer.java
new file mode 100644
index 0000000..116d3dd
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeatureContentConsumer.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Feature content consumer.
+ * A feature content consumer is an abstraction of each feature internal
+ * packaging mechanism. It allows content to be stored into a feature in
+ * a standard way regardless of the packaging mechanism used. Only concrete
+ * features that support storing need to implement a content consumer.
+ * The platform implements at least one feature type supporting content
+ * consumer. This is the feature type representing a locally-installed
+ * feature.
+ * <p>
+ * A feature content consumer delegates the storage of plug-in and
+ * non-plug-in files to a generic content consumer.
+ * </p>
+ * <p>
+ * Clients may implement this interface. However, in most cases clients
+ * will only use the feature content consumer provided by the feature type(s)
+ * implemented by the platform.
+ * </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>
+ * @see org.eclipse.update.core.IContentConsumer
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IFeatureContentConsumer {
+
+
+ /**
+ * Store a feature file.
+ * Note that only the feature definition files should be stored using
+ * this method. Plug-in files and non-plug-in data files should be
+ * stored using the content consumers corresponding to their respective
+ * entries.
+ *
+ * @see #open(IPluginEntry)
+ * @see #open(INonPluginEntry)
+ * @param contentReference content reference to feature file
+ * @param monitor progress monitor, can be <code>null</code>
+ * @exception CoreException
+ * @since 2.0
+ */
+ public void store(ContentReference contentReference, IProgressMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Opens a generic content consumer for the specified plug-in entry.
+ * Plug-in files corresponding to this entry should be stored
+ * using this content consumer.
+ *
+ * @param pluginEntry plug-in entry
+ * @return generic content consumer for the entry
+ * @exception CoreException
+ * @since 2.0
+ */
+ public IContentConsumer open(IPluginEntry pluginEntry) throws CoreException;
+
+ /**
+ * Opens a generic content consumer for the specified non-plug-in entry.
+ * Non-plug-in files corresponding to this entry should be stored
+ * using this content consumer.
+ *
+ * @param nonPluginEntry non-plug-in entry
+ * @return generic content consumer for the entry
+ * @exception CoreException
+ * @since 2.0
+ */
+ public IContentConsumer open(INonPluginEntry nonPluginEntry)
+ throws CoreException;
+
+ /**
+ * Closes this content consumer. This indicates a successful completion
+ * of the store operations. The content consumer commits any changes
+ * made by this consumer.
+ *
+ * @return reference to the newly populated feature
+ * @exception CoreException
+ * @since 2.0
+ */
+ public IFeatureReference close() throws CoreException;
+
+ /**
+ * Closes this content consumer, indicating the store operations should
+ * be aborted. The content consumer attempts to back out any changes
+ * made by this content consumer.
+ *
+ * @exception CoreException
+ * @since 2.0
+ */
+ public void abort() throws CoreException;
+
+ /**
+ * Sets the feature for this content consumer.
+ * In general, this method should only be called as part of
+ * feature creation. Once set, the feature should not be reset.
+ *
+ * @param feature feature for this content consumer
+ * @since 2.0
+ */
+ public void setFeature(IFeature feature);
+
+ /**
+ * Returns the feature for this content consumer.
+ *
+ * @return the feature for this content consumer
+ * @since 2.0
+ */
+ public IFeature getFeature();
+
+ /**
+ * Sets the parent for this content consumer.
+ * In general, this method should only be called as part of
+ * feature creation. Once set, the feature should not be reset.
+ *
+ * @param parent parent feature content consumer.
+ * @since 2.0
+ */
+ public void setParent(IFeatureContentConsumer parent);
+
+ /**
+ * Returns the feature content consumer that opened
+ * this feature content consumer, or <code>null</code>
+ * if this feature content consumer is a root feature
+ * content consumer.
+ *
+ * @return the parent feature content consumer, or null.
+ * @since 2.0
+ */
+ public IFeatureContentConsumer getParent();
+
+ /**
+ * Link the content consumer of the feature as a child
+ * content consumer
+ *
+ * @param feature the child feature.
+ * @throws CoreException
+ * @since 2.0
+ */
+ public void addChild(IFeature feature) throws CoreException;
+
+ /**
+ * Returns the feature content consumers that
+ * this feature content consumer opened
+ *
+ * @return an array of feature content consumer, or en empty array.
+ * @since 2.0
+ */
+ public IFeatureContentConsumer[] getChildren();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeatureContentProvider.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeatureContentProvider.java
new file mode 100644
index 0000000..d09f6f1
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeatureContentProvider.java
@@ -0,0 +1,270 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Feature content provider.
+ * A feature content provider is an abstraction of each feature internal
+ * packaging structure. It allows the feature content to be accessed in
+ * a standard way regardless of the internal packaging. All concrete feature
+ * implementations need to implement a feature content provider.
+ * <p>
+ * There are two ways of looking at a feature content:
+ * <ol>
+ * <li>the "logical" view, which is a representation of the actual files that
+ * make up the feature. These include any files that describe the feature
+ * itself, files that are the actual implementation of referenced plug-ins,
+ * and files that are the non-plug-in data files associated with the feature
+ * <li>the "packaged" view, which is a set of related archive files that
+ * contain the "logical" files.
+ * </ol>
+ * It is the responsibility of a feature content provider to manage the
+ * mapping between the "packaged" and "logical" views.
+ * </p>
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.FeatureContentProvider
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IFeatureContentProvider {
+
+ /**
+ * Returns the feature url.
+ * The exact interpretation of this URL is specific to each content
+ * provider. Typically, the URL is a reference to a file that can be
+ * used directly, or indirectly, to determine the content of the feature.
+ *
+ * @return feature url
+ * @since 2.0
+ */
+ public URL getURL();
+
+ /**
+ * Returns a content reference to the feature manifest. The feature manifest
+ * is an xml file, whose format is specified by the platform. Typically
+ * a feature will contain the manifest as one of the packaged files.
+ * For features that do not contain the manifest, or contain a manifest
+ * that does not follow the specified format, this method returns
+ * a reference to a computed manifest in the appropriate platform
+ * format.
+ *
+ * @param monitor progress monitor, can be <code>null</code>
+ * @return feature manifest reference, or <code>null</code> if the manifest cannot be found.
+ * @since 2.0
+ */
+ public ContentReference getFeatureManifestReference(InstallMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Returns an array of content references of all the "packaged"
+ * archives that make up this feature.
+ * <p>
+ * The number of returned references is dependent on each feature
+ * content provider (i.e is dependent on the packaging mechanism used
+ * by the particular feature type).
+ * </p>
+ *
+ * @param monitor progress monitor, can be <code>null</code>
+ * @return an array of references, or an empty array if no references
+ * are found
+ * @exception CoreException
+ * @since 2.0
+ */
+ public ContentReference[] getArchiveReferences(InstallMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Returns an array of content references of the "packaged"
+ * archives that contain the feature descriptive information.
+ * <p>
+ * In general, the feature descriptive information should be packaged
+ * separately from the "bulk" of the actual feature content.
+ * The feature entry archive(s) must be downloaded from an update
+ * site in order to present information about the feature to the
+ * client. Consequently, keeping the number and size of the feature
+ * entry archive(s) to a minimum will speed up the responsiveness of the
+ * user interface.
+ * </p>
+ * <p>
+ * The number of returned references is dependent on each feature
+ * content provider (i.e is dependent on the packaging mechanism used
+ * by the particular feature type).
+ * </p>
+ *
+ * @see IFeatureContentProvider#getFeatureEntryContentReferences(InstallMonitor)
+ * @param monitor progress monitor, can be <code>null</code>
+ * @return an array of references, or an empty array if no references
+ * are found
+ * @exception CoreException
+ * @since 2.0
+ */
+ public ContentReference[] getFeatureEntryArchiveReferences(InstallMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Returns an array of content references of the "packaged"
+ * archives that contain the files for the specified plug-in entry.
+ * <p>
+ * The number of returned references is dependent on each feature
+ * content provider (i.e is dependent on the packaging mechanism used
+ * by the particular feature type).
+ * </p>
+ *
+ * @see IFeatureContentProvider#getPluginEntryContentReferences(IPluginEntry, InstallMonitor)
+ * @param pluginEntry plug-in entry
+ * @param monitor progress monitor, can be <code>null</code>
+ * @return an array of references, or an empty array if no references
+ * are found
+ * @exception CoreException
+ * @since 2.0
+ */
+ public ContentReference[] getPluginEntryArchiveReferences(
+ IPluginEntry pluginEntry,
+ InstallMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Returns an array of content references of the "packaged"
+ * archives that contain the files for the specified non-plug-in entry.
+ * <p>
+ * The number of returned references is dependent on each feature
+ * content provider (i.e is dependent on the packaging mechanism used
+ * by the particular feature type).
+ * </p>
+ * <p>
+ * Note, that the platform does not interpret non-plug-in entries in any
+ * way, other that performing any required downloads. Non-plug-in entries
+ * are handled by custom install handlers that must be specified for
+ * the feature. Consequently, this interface does not make a distinction
+ * between the "logical" and "packaged" views for non-plug-in entries.
+ * The "packaged" view (returning references to the non-plug-in archives)
+ * is the only one supported. It is the responsibility of the custom install
+ * handler to understand the "logical" view of non-plug-in archives.
+ * </p>
+ *
+ * @param monitor progress monitor, can be <code>null</code>
+ * @return an array of references, or an empty array if no references
+ * are found
+ * @exception CoreException
+ * @since 2.0
+ */
+ public ContentReference[] getNonPluginEntryArchiveReferences(
+ INonPluginEntry nonPluginEntry,
+ InstallMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Returns an array of content references to the feature definition files
+ * (i.e the "logical" view of the files defining the feature). These
+ * are the files required to present information about the feature to the
+ * client, and in general, should not contain references to plug-in and
+ * non-plug-in files.
+ *
+ * @see IFeatureContentProvider#getFeatureEntryArchiveReferences(InstallMonitor)
+ * @param monitor progress monitor, can be <code>null</code>
+ * @return an array of ContentReference or an empty array if no references are found
+ * @exception CoreException when an error occurs
+ * @since 2.0
+ */
+ public ContentReference[] getFeatureEntryContentReferences(InstallMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Returns an array of content references to the files implementing
+ * the specified plug-in. (i.e the "logical" view of the plug-in).
+ *
+ * @see IFeatureContentProvider#getPluginEntryArchiveReferences(IPluginEntry, InstallMonitor)
+ * @param monitor progress monitor, can be <code>null</code>
+ * @return an array of ContentReference or an empty array if no references are found
+ * @exception CoreException
+ * @since 2.0
+ */
+ public ContentReference[] getPluginEntryContentReferences(
+ IPluginEntry pluginEntry,
+ InstallMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Returns the total size of all archives required for the
+ * specified plug-in and non-plug-in entries (the "packaging" view).
+ *
+ * @param pluginEntries an array of plug-in entries
+ * @param nonPluginEntries an array of non-plug-in entries
+ * @return total download size, or an indication that size could not be
+ * determined
+ * @see org.eclipse.update.core.model.ContentEntryModel#UNKNOWN_SIZE
+ * @since 2.0
+ */
+ public long getDownloadSizeFor(
+ IPluginEntry[] pluginEntries,
+ INonPluginEntry[] nonPluginEntries);
+
+ /**
+ * Returns the total size of all files required for the
+ * specified plug-in and non-plug-in entries (the "logical" view).
+ *
+ * @param pluginEntries an array of plug-in entries
+ * @param nonPluginEntries an array of non-plug-in entries
+ * @return total download size, or an indication that size could not be
+ * determined
+ * @see org.eclipse.update.core.model.ContentEntryModel#UNKNOWN_SIZE
+ * @since 2.0
+ */
+ public long getInstallSizeFor(
+ IPluginEntry[] pluginEntries,
+ INonPluginEntry[] nonPluginEntries);
+
+ /**
+ * Returns the verifier for this feature.
+ * If provided, the verifier is called at various point during
+ * installation processing to verify downloaded archives. The
+ * type of verification provided is dependent on the content
+ * provider implementation.
+ *
+ * @return verifier
+ * @exception CoreException
+ * @since 2.0
+ */
+ public IVerifier getVerifier() throws CoreException;
+
+ /**
+ * Returns the feature associated with this content provider.
+ *
+ * @return feature for this content provider
+ * @since 2.0
+ */
+ public IFeature getFeature();
+
+ /**
+ * Sets the feature associated with this content provider.
+ * In general, this method should only be called as part of
+ * feature creation. Once set, the feature should not be reset.
+ *
+ * @param feature feature for this content provider
+ * @since 2.0
+ */
+ public void setFeature(IFeature feature);
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeatureFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeatureFactory.java
new file mode 100644
index 0000000..7e0736d
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeatureFactory.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Feature factory interface.
+ * A feature factory is used to construct new instances of concrete
+ * features.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.BaseFeatureFactory
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IFeatureFactory {
+
+ /**
+ * Returns a feature defined by the supplied URL. The feature
+ * is associated with the specified site.
+ * <p>
+ * The actual interpretation of the URL is feature-type specific.
+ * In most cases the URL will point to some feature-specific
+ * file that can be used (directly or indirectly) to construct
+ * the feature object.
+ * </p>
+ * @param url URL interpreted by the feature
+ * @param site site to be associated with the feature
+ * @return concrete feature object
+ * @exception CoreException
+ * @deprecated use createFeature(URL, ISite, IProgressMonitor) instead
+ * @since 2.0
+ */
+ public IFeature createFeature(URL url, ISite site) throws CoreException;
+
+ /**
+ * Returns a feature defined by the supplied URL. The feature
+ * is associated with the specified site.
+ * <p>
+ * The actual interpretation of the URL is feature-type specific.
+ * In most cases the URL will point to some feature-specific
+ * file that can be used (directly or indirectly) to construct
+ * the feature object.
+ * </p>
+ * @param url URL interpreted by the feature
+ * @param site site to be associated with the feature
+ * @return concrete feature object
+ * @exception CoreException
+ * @since 2.1
+ */
+ public IFeature createFeature(URL url, ISite site, IProgressMonitor monitor) throws CoreException;
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeatureReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeatureReference.java
new file mode 100644
index 0000000..e8bd3a3
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IFeatureReference.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Feature reference.
+ * A reference to a feature.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.FeatureReference
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IFeatureReference extends IAdaptable,IPlatformEnvironment {
+
+ /**
+ * Returns the referenced feature URL.
+ *
+ * @return feature URL
+ * @since 2.0
+ */
+ public URL getURL();
+
+ /**
+ * Returns the update site for the referenced feature
+ *
+ * @return feature site
+ * @since 2.0
+ */
+ public ISite getSite();
+
+ /**
+ * Returns the label for the referenced feature
+ *
+ * @return the label
+ * @since 2.1
+ */
+ public String getName();
+
+
+ /**
+ * Returns the referenced feature.
+ * This is a factory method that creates the full feature object.
+ *
+ * @return the referenced feature
+ * @deprecated use getFeature(IProgressMonitor) instead
+ * @since 2.0
+ */
+ public IFeature getFeature() throws CoreException;
+
+ /**
+ * Returns the referenced feature.
+ * This is a factory method that creates the full feature object.
+ *
+ * @param monitor the progress monitor
+ * @return the referenced feature
+ * @since 2.1
+ */
+ public IFeature getFeature(IProgressMonitor monitor) throws CoreException;
+
+
+ /**
+ * Returns the feature identifier.
+ *
+ * @return the feature identifier.
+ * @exception CoreException
+ * @since 2.0
+ */
+ public VersionedIdentifier getVersionedIdentifier() throws CoreException;
+
+ /**
+ * Sets the feature reference URL.
+ * This is typically performed as part of the feature reference creation
+ * operation. Once set, the url should not be reset.
+ *
+ * @param url reference URL
+ * @since 2.0
+ */
+ public void setURL(URL url) throws CoreException;
+
+ /**
+ * Associates a site with the feature reference.
+ * This is typically performed as part of the feature reference creation
+ * operation. Once set, the site should not be reset.
+ *
+ * @param site site for the feature reference
+ * @since 2.0
+ */
+ public void setSite(ISite site);
+
+ /**
+ * Returns <code>true</code> if this feature is patching another feature,
+ * <code>false</code> otherwise
+ * @return boolean
+ * @since 2.1
+ */
+ public boolean isPatch();
+
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IImport.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IImport.java
new file mode 100644
index 0000000..4dc6c70
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IImport.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * Plug-in dependency entry.
+ * Describes a feature dependency on a particular plug-in. The dependency
+ * can specify a specific plug-in version and a matching rule for
+ * satisfying the dependency.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.Import
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IImport extends IAdaptable, IUpdateConstants, IPlatformEnvironment {
+
+ /**
+ * The import relates to a plugin
+ * @since 2.0.2
+ */
+ public static final int KIND_PLUGIN = 0;
+
+ /**
+ * The import relates to a feature
+ * @since 2.0.2
+ */
+ public static final int KIND_FEATURE = 1;
+
+ /**
+ * Returns an identifier of the dependent plug-in.
+ *
+ * @return plug-in identifier
+ * @since 2.0
+ */
+ public VersionedIdentifier getVersionedIdentifier();
+
+ /**
+ * Returns the matching rule for the dependency.
+ *
+ * @return matching rule
+ * @since 2.0
+ */
+ public int getRule();
+
+ /**
+ * Returns the matching rule for the dependency identifier.
+ *
+ * @return matching id rule
+ * @since 2.1
+ */
+ public int getIdRule();
+
+ /**
+ * Returns the dependency kind
+ *
+ * @see #KIND_PLUGIN
+ * @see #KIND_FEATURE
+ * @return KIND_PLUGIN if the dependency relates to a plugin,
+ * KIND_FEATURE if the dependency relates to a feature.
+ */
+ public int getKind();
+
+ /**
+ * Returns the patch mode. If the import is in patch mode,
+ * the referenced feature is considered a patch target,
+ * and the feature that owns the import is patch carrier.
+ * Patch carrier and patched feature are linked in a
+ * distinct way: if a patched feature is disabled,
+ * all the patches are disabled with it.
+ * @return true if the element represents a patch
+ * reference, false otherwise.
+ */
+ public boolean isPatch();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IIncludedFeatureReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IIncludedFeatureReference.java
new file mode 100644
index 0000000..7511a62
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IIncludedFeatureReference.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.update.configuration.IConfiguredSite;
+
+
+
+/**
+ * Included Feature reference.
+ * A reference to a included feature.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.FeatureReference
+ * @since 2.0.1
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IIncludedFeatureReference extends IFeatureReference, IAdaptable {
+
+ /**
+ * Returns the referenced feature.
+ * This is a factory method that creates the full feature object.
+ * equivalent to getFeature(false,null);
+ *
+ * @return the referenced feature
+ * @deprecated use getFeature(IProgressMonitor)
+ * @since 2.0
+ */
+ public IFeature getFeature() throws CoreException;
+
+ /**
+ * Returns the referenced feature.
+ * This is a factory method that creates the full feature object.
+ *
+ * @param perfectMatch <code>true</code> if the perfect match feature feature should be returned
+ * <code>false</code> if the best match feature should be returned.
+ * @param configuredSite the configured site to search for the Feature. If
+ * the configured site is <code>null</code> the search will be done in the current configured site.
+ * @return the referenced feature
+ * instead
+ * @since 2.0.2
+ * <b>Note:</b> This method 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.
+ * @deprecated use getFeature(IProgressMonitor)
+ */
+ public IFeature getFeature(boolean perfectMatch,IConfiguredSite configuredSite) throws CoreException;
+
+ /**
+ * Returns the referenced feature.
+ * This is a factory method that creates the full feature object.
+ *
+ * @param perfectMatch <code>true</code> if the perfect match feature feature should be returned
+ * <code>false</code> if the best match feature should be returned.
+ * @param configuredSite the configured site to search for the Feature. If
+ * the configured site is <code>null</code> the search will be done in the current configured site.
+ * @param monitor the progress monitor
+ * @return the referenced feature
+ * @since 2.1
+ * <b>Note:</b> This method 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.
+ * @deprecated use getFeature(IProgressMonitor)
+ */
+ public IFeature getFeature(boolean perfectMatch,IConfiguredSite configuredSite, IProgressMonitor monitor) throws CoreException;
+
+
+ /**
+ * Returns <code>true</code> if the feature is optional, <code>false</code> otherwise.
+ *
+ * @return boolean
+ * @since 2.0.1
+ */
+ public boolean isOptional();
+
+ /**
+ * Returns the matching rule for this included feature.
+ * The rule will determine the ability of the included feature to move version
+ * without causing the overall feature to appear broken.
+ *
+ * The default is <code>RULE_PERFECT</code>
+ *
+ * @see IUpdateConstants#RULE_PERFECT
+ * @see IUpdateConstants#RULE_EQUIVALENT
+ * @see IUpdateConstants#RULE_COMPATIBLE
+ * @see IUpdateConstants#RULE_GREATER_OR_EQUAL
+ * @return int representation of feature matching rule.
+ * @since 2.0.2
+ * @deprecated since 3.0 included feature version is exactly specified
+ */
+ public int getMatch();
+
+ /**
+ * Returns the search location for this included feature.
+ * The location will be used to search updates for this feature.
+ *
+ * The default is <code>SEARCH_ROOT</code>
+ *
+ * @see IUpdateConstants#SEARCH_ROOT
+ * @see IUpdateConstants#SEARCH_SELF
+ * @return int representation of feature searching rule.
+ * @since 2.0.2
+ */
+
+ public int getSearchLocation();
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IInstallHandler.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IInstallHandler.java
new file mode 100644
index 0000000..a18790a
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IInstallHandler.java
@@ -0,0 +1,247 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Custom install handler.
+ * Custom install handlers can optionally be associated with a feature.
+ * The actual install handler implementation can be physically delivered
+ * as part of the feature package, or can already be installed on the client
+ * machine and registered via the <code>org.eclipse.update.core.installHandlers</code>
+ * extension point. The install handler methods are called at predetermined
+ * point during update actions.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly subclass the provided implementation of this interface.
+ * </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>
+ * @see org.eclipse.update.core.BaseInstallHandler
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IInstallHandler {
+
+ /**
+ * Indicates the handler is being initialized for feature install.
+ * @since 2.0
+ */
+ public static final int HANDLER_ACTION_INSTALL = 1;
+
+ /**
+ * Indicates the handler is being initialized for feature configure.
+ * @since 2.0
+ */
+ public static final int HANDLER_ACTION_CONFIGURE = 2;
+
+ /**
+ * Indicates the handler is being initialized for feature unconfigure.
+ * @since 2.0
+ */
+ public static final int HANDLER_ACTION_UNCONFIGURE = 3;
+
+ /**
+ * Indicates the handler is being initialized for feature uninstall.
+ * @since 2.0
+ */
+ public static final int HANDLER_ACTION_UNINSTALL = 4;
+
+ /**
+ * Initialize the install handler.
+ * Install handlers are always constructed using the default constructor.
+ * The are initialized immediately following construction.
+ *
+ * @param type update action type
+ * @param feature the target of the action
+ * @param entry model entry that defines this handler
+ * @param monitor optional progress monitor, can be <code>null</code>
+ * @exception CoreException
+ * @since 2.0
+ */
+ public void initialize(
+ int type,
+ IFeature feature,
+ IInstallHandlerEntry entry,
+ InstallMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Called at the start of the install action. At this point, no install
+ * processing has taken place.
+ *
+ * @see #HANDLER_ACTION_INSTALL
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void installInitiated() throws CoreException;
+
+ /**
+ * Called after files corresponding to plug-in entries have been downloaded,
+ * but before they are actully unpacked and installed.
+ *
+ * @see #HANDLER_ACTION_INSTALL
+ * @param plugins downloaded plug-in entries. Note this may be a subset
+ * of the plug-ins actually references by the feature.
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void pluginsDownloaded(IPluginEntry[] plugins) throws CoreException;
+
+ /**
+ * Called after files corresponding to non-plug-in entries have been
+ * downloaded. The custom install handler can perform any custom
+ * verification of the non-plug-in entries (these are not interpreted
+ * in any way by the platform (beyond downloading)).
+ *
+ * @see #HANDLER_ACTION_INSTALL
+ * @param nonPluginData downloaded non-plug-in entries.
+ * @param listener verification listener, may be <code>null</code>.
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void nonPluginDataDownloaded(
+ INonPluginEntry[] nonPluginData,
+ IVerificationListener listener)
+ throws CoreException;
+
+ /**
+ * Called after the feature files and any downloaded plug-ins have
+ * been installed. Typically this is the point where the custom
+ * install handler can install any non-plug-in entries (these are not
+ * interpreted in any way by the platform (beyond downloading)).
+ *
+ * @see #HANDLER_ACTION_INSTALL
+ * @param consumer content consumer for the feature. The install handler
+ * can choose to use this consumer to install the non-plug-in data,
+ * or can handle the data in any other way. If using the consumer,
+ * the install handler should only call
+ * @see IFeatureContentConsumer#store(ContentReference, IProgressMonitor)
+ * and @see IFeatureContentConsumer#open(INonPluginEntry)
+ * methods of the consumer.
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void completeInstall(IFeatureContentConsumer consumer)
+ throws CoreException;
+
+ /**
+ * Called at the end of the install action.
+ *
+ * @see #HANDLER_ACTION_INSTALL
+ * @param success indicates action success.
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void installCompleted(boolean success) throws CoreException;
+
+ /**
+ * Called at the start of the configure action
+ *
+ * @see #HANDLER_ACTION_CONFIGURE
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void configureInitiated() throws CoreException;
+
+ /**
+ * Called after the feature has been configured. The install handler
+ * should perform any completion tasks. No arguments are passed
+ * to the method. If needed, the install handler can use arguments
+ * passed on the initialization call.
+ *
+ * @see #HANDLER_ACTION_CONFIGURE
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void completeConfigure() throws CoreException;
+
+ /**
+ * Called at the end of the configure action.
+ *
+ * @see #HANDLER_ACTION_CONFIGURE
+ * @param success indicates action success.
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void configureCompleted(boolean success) throws CoreException;
+
+ /**
+ * Called at the start of the unconfigure action
+ *
+ * @see #HANDLER_ACTION_UNCONFIGURE
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void unconfigureInitiated() throws CoreException;
+
+ /**
+ * Called after the feature has been unconfigured. The install handler
+ * should perform any completion tasks. No arguments are passed
+ * to the method. If needed, the install handler can use arguments
+ * passed on the initialization call.
+ *
+ * @see #HANDLER_ACTION_UNCONFIGURE
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void completeUnconfigure() throws CoreException;
+
+ /**
+ * Called at the end of the unconfigure action.
+ *
+ * @see #HANDLER_ACTION_UNCONFIGURE
+ * @param success indicates action success.
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void unconfigureCompleted(boolean success) throws CoreException;
+
+ /**
+ * Called at the start of the uninstall action
+ *
+ * @see #HANDLER_ACTION_UNINSTALL
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void uninstallInitiated() throws CoreException;
+
+ /**
+ * Called after the feature has been uninstalled. The install handler
+ * should perform any completion tasks. No arguments are passed
+ * to the method. If needed, the install handler can use arguments
+ * passed on the initialization call. Note, that at this point
+ * the feature files and any unreferenced plug-ins have been
+ * removed.
+ *
+ * @see #HANDLER_ACTION_UNINSTALL
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void completeUninstall() throws CoreException;
+
+ /**
+ * Called at the end of the uninstall action.
+ *
+ * @see #HANDLER_ACTION_UNINSTALL
+ * @param success indicates action success.
+ * @exception CoreException terminates the action
+ * @since 2.0
+ */
+ public void uninstallCompleted(boolean success) throws CoreException;
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IInstallHandlerEntry.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IInstallHandlerEntry.java
new file mode 100644
index 0000000..206cece
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IInstallHandlerEntry.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * Install handler entry.
+ * Associates an optional custom install handler with the feature.
+ * Install handlers must implement the IInstallHandler interface.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.InstallHandlerEntry
+ * @see org.eclipse.update.core.IInstallHandler
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IInstallHandlerEntry extends IAdaptable {
+
+ /**
+ * Returns optional URL used for browser-triggered installation handling.
+ *
+ * @return url
+ * @since 2.0
+ */
+ public URL getURL();
+
+ /**
+ * Returns optional name of a library containing the install
+ * handler classes. If specified, the referenced library
+ * must be contained in the feature archive.
+ *
+ * @return install handler library name
+ * @since 2.0
+ */
+ public String getLibrary();
+
+ /**
+ * Returns install handler name.
+ * It is interpreted depending on the value of the library
+ * specification. If library is not specified, the name
+ * is intepreted as an identifier of a "global" install
+ * handler registered in the <code>org.eclipse.update.core.installHandlers</code>
+ * extension point. If library is specified, the name is interpreted
+ * as a fully qualified name of a class contained in the
+ * library. In both cases, the resulting class must
+ * implement IInstallHandler. The class is dynamically loaded and
+ * called at specific points during feature processing.
+ * The handler has visibility to the API classes from the update plug-in,
+ * and plug-ins required by the update plugin.
+ *
+ * @see IInstallHandler
+ * @return handler name
+ * @since 2.0
+ */
+ public String getHandlerName();
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IInstallHandlerWithFilter.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IInstallHandlerWithFilter.java
new file mode 100644
index 0000000..30ae8ea
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IInstallHandlerWithFilter.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+/**
+ * Custom install handler.
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IInstallHandlerWithFilter extends IInstallHandler{
+
+ public boolean acceptNonPluginData(INonPluginEntry data);
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/INonPluginEntry.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/INonPluginEntry.java
new file mode 100644
index 0000000..7bd158d
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/INonPluginEntry.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * Non-plug-in entry defines an arbitrary non-plug-in data file packaged
+ * as part of a feature. Non-plug-in entries are not interpreted by the
+ * platform (other than being downloaded as part of an install action).
+ * They require a custom install handler to be specified as part of the
+ * feature. Note, that defining a non-plug-in entry does not necessarily
+ * indicate the non-plug-in file is packaged together with any other
+ * feature files. The actual packaging details are determined by the
+ * feature content provider for the feature.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.NonPluginEntry
+ * @see org.eclipse.update.core.FeatureContentProvider
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface INonPluginEntry extends IPlatformEnvironment, IAdaptable {
+
+ /**
+ * Returns the identifier of this data entry.
+ *
+ * @return data entry identifier
+ * @since 2.0
+ */
+ public String getIdentifier();
+
+ /**
+ * Returns the download size of the entry, if it can be determined.
+ *
+ * @see org.eclipse.update.core.model.ContentEntryModel#UNKNOWN_SIZE
+ * @return download size of the feature in KiloBytes, or an indication
+ * the size could not be determined
+ * @since 2.0
+ */
+ public long getDownloadSize();
+
+ /**
+ * Returns the install size of the feature, if it can be determined.
+ *
+ * @see org.eclipse.update.core.model.ContentEntryModel#UNKNOWN_SIZE
+ * @return install size of the feature in KiloBytes, or an indication
+ * the size could not be determined
+ * @since 2.0
+ */
+ public long getInstallSize();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IPlatformEnvironment.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IPlatformEnvironment.java
new file mode 100644
index 0000000..bad0bfb
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IPlatformEnvironment.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.*;
+
+/**
+ * Plug-in entry defines a packaging reference from a feature to a plug-in.
+ * It indicates that the referenced plug-in is to be considered as
+ * part of the feature. Note, that this does not necessarily indicate
+ * that the plug-in files are packaged together with any other
+ * feature files. The actual packaging details are determined by the
+ * feature content provider for the feature.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.PluginEntry
+ * @see org.eclipse.update.core.FeatureContentProvider
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IPlatformEnvironment extends IAdaptable {
+
+
+ /**
+ * Returns optional operating system specification.
+ * A comma-separated list of os designators defined by the platform.
+ * Indicates this entry should only be installed on one of the specified
+ * os systems. If this attribute is not specified, or is <code>*</code>, the
+ * entry can be installed on all systems (portable implementation). If the
+
+ * This information is used as a hint by the installation and update
+ * support.
+ *
+ * @return the operating system specification, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getOS();
+
+ /**
+ * Returns optional system architecture specification.
+ * A comma-separated list of arch designators defined by the platform.
+ * Indicates this entry should only be installed on one of the specified
+ * systems. If this attribute is not specified, or is <code>*</code>, the
+ * entry can be installed on all systems (portable implementation).
+ *
+ * This information is used as a hint by the installation and update
+ * support.
+ *
+ * @return system architecture specification, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getWS();
+
+ /**
+ * Returns optional system architecture specification.
+ * A comma-separated list of arch designators defined by the platform.
+ * Indicates this entry should only be installed on one of the specified
+ * systems. If this attribute is not specified, or is <code>*</code>, the
+ * entry can be installed on all systems (portable implementation).
+ *
+ * This information is used as a hint by the installation and update
+ * support.
+ *
+ * @return system architecture specification, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getOSArch();
+
+ /**
+ * Returns optional locale specification.
+ * A comma-separated list of locale designators defined by Java.
+ * Indicates this entry should only be installed on a system running
+ * with a compatible locale (using Java locale-matching rules).
+ * If this attribute is not specified, or is <code>*</code>, the entry can
+ * be installed on all systems (language-neutral implementation).
+ *
+ * This information is used as a hint by the installation and update
+ * support.
+ *
+ * @return the locale specification, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getNL();
+
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IPluginEntry.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IPluginEntry.java
new file mode 100644
index 0000000..d3c2eb0
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IPluginEntry.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.*;
+
+/**
+ * Plug-in entry defines a packaging reference from a feature to a plug-in.
+ * It indicates that the referenced plug-in is to be considered as
+ * part of the feature. Note, that this does not necessarily indicate
+ * that the plug-in files are packaged together with any other
+ * feature files. The actual packaging details are determined by the
+ * feature content provider for the feature.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.PluginEntry
+ * @see org.eclipse.update.core.FeatureContentProvider
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IPluginEntry extends IPlatformEnvironment,IAdaptable {
+
+ /**
+ * Returns the identifier of this plugin entry
+ *
+ * @return plugin entry identifier
+ * @since 2.0
+ */
+ public VersionedIdentifier getVersionedIdentifier();
+
+ /**
+ * Returns an indication whethyer this entry represents a fragment.
+ *
+ * @return <code>true</code> if the entry represents a plug-in fragment,
+ * <code>false</code> if the entry represents a plug-in
+ * @since 2.0
+ */
+ public boolean isFragment();
+
+ /**
+ * Returns the download size of the entry, if it can be determined.
+ *
+ * @see org.eclipse.update.core.model.ContentEntryModel#UNKNOWN_SIZE
+ * @return download size of the feature in KiloBytes, or an indication
+ * the size could not be determined
+ * @since 2.0
+ */
+ public long getDownloadSize();
+
+ /**
+ * Returns the install size of the feature, if it can be determined.
+ *
+ * @see org.eclipse.update.core.model.ContentEntryModel#UNKNOWN_SIZE
+ * @return install size of the feature in KiloBytes, or an indication
+ * the size could not be determined
+ * @since 2.0
+ */
+ public long getInstallSize();
+
+ /**
+ * Sets the identifier of this plugin entry.
+ * This is typically performed as part of the plug-in entry creation
+ * operation. Once set, the identifier should not be reset.
+ *
+ * @param identifier plugin entry identifier
+ * @since 2.0
+ */
+ public void setVersionedIdentifier(VersionedIdentifier identifier);
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/ISite.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/ISite.java
new file mode 100644
index 0000000..663bf80
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/ISite.java
@@ -0,0 +1,330 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.model.*;
+
+/**
+ * Site represents a location containing some number of features (packaged
+ * or installed). Sites are treated purely as an installation and packaging
+ * construct. They do not play a role during Eclipse plug-in execution.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.Site
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface ISite extends IAdaptable {
+
+ /**
+ * Default type for an installed feature. Different concrete feature
+ * implementations can be registered together with their corresponding type
+ * using the <code>org.eclipse.update.core.featureTypes</code>
+ * extension point.
+ *
+ * @since 2.0
+ */
+ public static final String DEFAULT_INSTALLED_FEATURE_TYPE = "org.eclipse.update.core.installed"; //$NON-NLS-1$
+
+ /**
+ * Default type for a packaged feature. Different concrete feature
+ * implementations can be registered together with their corresponding type
+ * using the <code>org.eclipse.update.core.featureTypes</code>
+ * extension point.
+ *
+ * @since 2.0
+ */
+ public static final String DEFAULT_PACKAGED_FEATURE_TYPE = "org.eclipse.update.core.packaged"; //$NON-NLS-1$
+
+ /**
+ * If we are unable to access a site, the returned CoreException will contain
+ * this return code.
+ *
+ * @since 2.0.1
+ */
+ public static final int SITE_ACCESS_EXCEPTION = 42;
+
+ /**
+ * Returns the site URL
+ *
+ * @return site URL
+ * @since 2.0
+ */
+ public URL getURL();
+
+ /**
+ * Return the site type. Different concrete site implementations can be
+ * registered together with their corresponding type using the
+ * <code>org.eclipse.update.core.siteTypes</code> extension point.
+ *
+ * @return site type, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getType();
+
+ /**
+ * Returns the site description.
+ *
+ * @return site description, or <code>null</code>.
+ * @since 2.0
+ */
+ public IURLEntry getDescription();
+
+ /**
+ * Returns an array of categories defined by the site.
+ *
+ * @return array of site categories, or an empty array.
+ * @since 2.0
+ */
+ public ICategory[] getCategories();
+
+ /**
+ * Returns the named site category.
+ *
+ * @param name category name
+ * @return named category, or <code>null</code> ifit does not exist
+ * @since 2.0
+ */
+ public ICategory getCategory(String name);
+
+ /**
+ * Returns an array of references to features on this site.
+ *
+ * @return an array of feature references, or an empty array.
+ * @since 2.0
+ */
+ public ISiteFeatureReference[] getFeatureReferences();
+
+ /**
+ * Returns an array of references to features on this site.
+ * No filtering occurs.
+ *
+ * @return an array of feature references, or an empty array..
+ * @since 2.1
+ */
+ public ISiteFeatureReference[] getRawFeatureReferences();
+
+ /**
+ * Returns a reference to the specified feature if
+ * it is installed on this site.
+ * filtered by the operating system, windowing system and architecture
+ * system set in <code>Sitemanager</code>
+ *
+ * @param feature feature
+ * @return feature reference, or <code>null</code> if this feature
+ * cannot be located on this site.
+ * @since 2.0
+ */
+ public ISiteFeatureReference getFeatureReference(IFeature feature);
+
+ /**
+ * Returns an array of plug-in and non-plug-in archives located
+ * on this site
+ *
+ * @return an array of archive references, or an empty array if there are
+ * no archives known to this site. Note, that an empty array does not
+ * necessarily indicate there are no archives accessible on this site.
+ * It simply indicates the site has no prior knowledge of such archives.
+ * @since 2.0
+ */
+ public IArchiveReference[] getArchives();
+
+ /**
+ * Returns the content provider for this site. A content provider
+ * is an abstraction of each site organization. It allows the
+ * content of the site to be accessed in a standard way
+ * regardless of the organization. All concrete sites
+ * need to be able to return a content provider.
+ *
+ * @return site content provider
+ * @exception CoreException
+ * @since 2.0
+ */
+ public ISiteContentProvider getSiteContentProvider() throws CoreException;
+
+ /**
+ * Returns the default type for a packaged feature supported by this site
+ *
+ * @return feature type, as registered in the
+ * <code>org.eclipse.update.core.featureTypes</code> extension point.
+ * @since 2.0
+ */
+ public String getDefaultPackagedFeatureType();
+
+ /**
+ * Returns an array of entries corresponding to plug-ins installed
+ * on this site.
+ *
+ * @return array of plug-in entries,or an empty array.
+ * @since 2.0
+ */
+ public IPluginEntry[] getPluginEntries();
+
+ /**
+ * Returns the number of plug-ins installed on this site
+ *
+ * @return number of installed plug-ins
+ * @since 2.0
+ */
+ public int getPluginEntryCount();
+
+ /**
+ * Adds a new plug-in entry to this site.
+ *
+ * @param pluginEntry plug-in entry
+ * @since 2.0
+ */
+ public void addPluginEntry(IPluginEntry pluginEntry);
+
+ /**
+ * Returns an array of entries corresponding to plug-ins that are
+ * installed on this site and are referenced only by the specified
+ * feature. These are plug-ins that are not shared with any other
+ * feature.
+ *
+ * @param feature feature
+ * @return an array of plug-in entries, or an empty array.
+ * @exception CoreException
+ * @since 2.0
+ */
+ public IPluginEntry[] getPluginEntriesOnlyReferencedBy(IFeature feature) throws CoreException;
+
+ /**
+ * Returns the size of the files that need to be downloaded in order
+ * to install the specified feature on this site, if it can be determined.
+ * This method takes into account any plug-ins that are already
+ * available on this site.
+ *
+ * @see org.eclipse.update.core.model.ContentEntryModel#UNKNOWN_SIZE
+ * @param feature candidate feature
+ * @return download size of the feature in KiloBytes, or an indication
+ * the size could not be determined
+ * @since 2.0
+ */
+ public long getDownloadSizeFor(IFeature feature);
+
+ /**
+ * Returns the size of the files that need to be installed
+ * for the specified feature on this site, if it can be determined.
+ * This method takes into account any plug-ins that are already
+ * installed on this site.
+ *
+ * @see org.eclipse.update.core.model.ContentEntryModel#UNKNOWN_SIZE
+ * @param feature candidate feature
+ * @return install size of the feature in KiloBytes, or an indication
+ * the size could not be determined
+ * @since 2.0
+ */
+ public long getInstallSizeFor(IFeature feature);
+
+ /**
+ * Installs the specified feature on this site.
+ *
+ * @param feature feature to install
+ * @param verificationListener install verification listener
+ * @param monitor install monitor, can be <code>null</code>
+ * @exception InstallAbortedException when the user cancels the install
+ * @exception CoreException
+ * @since 2.0
+ */
+ public IFeatureReference install(IFeature feature, IVerificationListener verificationListener, IProgressMonitor monitor) throws InstallAbortedException, CoreException;
+
+ /**
+ * Installs the specified feature on this site.
+ * Only optional features passed as parameter will be installed.
+ *
+ * @param feature feature to install
+ * @param optionalfeatures list of optional features to be installed
+ * @param verificationListener install verification listener
+ * @param monitor install monitor, can be <code>null</code>
+ * @exception InstallAbortedException when the user cancels the install
+ * @exception CoreException
+ * @since 2.0
+ */
+ public IFeatureReference install(IFeature feature, IFeatureReference[] optionalfeatures, IVerificationListener verificationListener, IProgressMonitor monitor) throws InstallAbortedException, CoreException;
+
+ /**
+ * Removes (uninstalls) the specified feature from this site. This method
+ * takes into account plug-in entries referenced by the specified fetaure
+ * that continue to be required by other features installed on this site.
+ *
+ * @param feature feature to remove
+ * @param monitor progress monitor
+ * @exception CoreException
+ * @since 2.0
+ */
+ public void remove(IFeature feature, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Sets the site content provider. This is typically performed
+ * as part of the site creation operation. Once set, the
+ * provider should not be reset.
+ *
+ * @param siteContentProvider site content provider
+ * @since 2.0
+ */
+ public void setSiteContentProvider(ISiteContentProvider siteContentProvider);
+
+ /**
+ * Returns the <code>IConfiguredSite</code> for this site in the current
+ * configuration or <code>null</code> if none found.
+ *
+ * @since 2.0.2
+ */
+ public IConfiguredSite getCurrentConfiguredSite();
+
+ /**
+ * Creates a new feature object. The feature must exist on this site
+ * or a core exception will be thrown. Concrete implementations
+ * may elect to cache instances, in which case subsequent calls
+ * to create a feature with the same URL will
+ * return the same instance.
+ * param type the feature type that will be used to select the factory. If
+ * <code>null</code> is passed, default feature type will be used.
+ * param url URL of the feature archive as listed in the site.
+ * return newly created feature object, or a cached value if
+ * caching is implemented by this site.
+ * @deprecated use createFeature(String,URL,IProgressMonitor) instead
+ * @since 2.0.2
+ */
+ IFeature createFeature(String type, URL url) throws CoreException;
+
+ /**
+ * Creates a new feature object. The feature must exist on this site
+ * or a core exception will be thrown. Concrete implementations
+ * may elect to cache instances, in which case subsequent calls
+ * to create a feature with the same URL will
+ * return the same instance.
+ * param type the feature type that will be used to select the factory. If
+ * <code>null</code> is passed, default feature type will be used.
+ * param url URL of the feature archive as listed in the site.
+ * return newly created feature object, or a cached value if
+ * caching is implemented by this site.
+ * @param monitor the progress monitor
+ * @since 2.1
+ */
+ IFeature createFeature(String type, URL url,IProgressMonitor monitor) throws CoreException;
+
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteContentProvider.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteContentProvider.java
new file mode 100644
index 0000000..be7c97b
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteContentProvider.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+
+/**
+ * Site content provider.
+ * A site content provider is an abstraction of each site internal
+ * organization. It allows the site content to be accessed in
+ * a standard way regardless of the internal organization. All concrete site
+ * implementations need to implement a site content provider.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.SiteContentProvider
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface ISiteContentProvider {
+
+ /**
+ * Returns the URL of this site
+ *
+ * @return site URL
+ * @since 2.0
+ */
+ public URL getURL();
+
+
+ /**
+ * Returns a URL for the identified archive
+ *
+ * @param id archive identifier
+ * @return archive URL, or <code>null</code>.
+ * @exception CoreException
+ * @since 2.0
+ */
+ public URL getArchiveReference(String id) throws CoreException;
+
+ /**
+ * Returns the site for this provider
+ *
+ * @return provider site
+ * @since 2.0
+ */
+ public ISite getSite();
+
+ /**
+ * Sets the site for this provider.
+ * In general, this method should only be called as part of
+ * site creation. Once set, the site should not be reset.
+ *
+ * @param site provider site
+ * @since 2.0
+ */
+ public void setSite(ISite site);
+}
+
+
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteFactory.java
new file mode 100644
index 0000000..9d908eb
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteFactory.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.model.*;
+
+/**
+ * Site factory interface.
+ * A site factory is used to construct new instances of concrete
+ * sites.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.BaseSiteFactory
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface ISiteFactory {
+
+ /**
+ * Returns a site defined by the supplied URL.
+ * <p>
+ * The actual interpretation of the URL is site-type specific.
+ * In most cases the URL will point to some site-specific
+ * file that can be used (directly or indirectly) to construct
+ * the site object.
+ * </p>
+ * @param url URL interpreted by the site
+ * @return site object
+ * @exception CoreException
+ * @exception InvalidSiteTypeException the referenced site type is
+ * not a supported type for this factory
+ * @since 2.0
+ */
+ public ISite createSite(URL url)
+ throws CoreException, InvalidSiteTypeException;
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteFactoryExtension.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteFactoryExtension.java
new file mode 100644
index 0000000..b0422b6
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteFactoryExtension.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.model.*;
+
+/**
+ * <p>
+ * This is an extension to the standard ISiteFactory interface.
+ * If a factory implements this interface and is handling
+ * URL connections, a progress monitor can be passed to
+ * allow canceling of frozen connections.
+ * </p>
+ * <p>Input stream is obtained from the connection on
+ * a separate thread. When connection is canceled,
+ * the thread is still active. It is allowed to terminate
+ * when the connection times out on its own.
+ * </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>
+ * @see org.eclipse.update.core.BaseSiteFactory
+ * @since 2.1
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface ISiteFactoryExtension {
+ /**
+ * Returns a site defined by the supplied URL.
+ * <p>
+ * The actual interpretation of the URL is site-type specific.
+ * In most cases the URL will point to some site-specific
+ * file that can be used (directly or indirectly) to construct
+ * the site object.
+ * </p>
+ * @param url URL interpreted by the site
+ * @param monitor a progress monitor that can be canceled
+ * @return site object
+ * @exception CoreException
+ * @exception InvalidSiteTypeException the referenced site type is
+ * not a supported type for this factory
+ * @since 2.0
+ */
+ public ISite createSite(URL url, IProgressMonitor monitor)
+ throws CoreException, InvalidSiteTypeException;
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteFeatureReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteFeatureReference.java
new file mode 100644
index 0000000..0ba2c01
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteFeatureReference.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.*;
+
+/**
+ * Site Feature reference.
+ * A reference to a feature on a particular update site.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.SiteFeatureReference
+ * @since 2.1
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface ISiteFeatureReference extends IFeatureReference, IAdaptable {
+
+ /**
+ * Returns an array of categories the referenced feature belong to.
+ *
+ * @return an array of categories, or an empty array
+ * @since 2.1
+ */
+ public ICategory[] getCategories();
+
+ /**
+ * Adds a category to the referenced feature.
+ *
+ * @param category new category
+ * @since 2.1
+ */
+ public void addCategory(ICategory category);
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteWithMirrors.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteWithMirrors.java
new file mode 100644
index 0000000..7a0ec9c
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/ISiteWithMirrors.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.*;
+
+/**
+ * An extension of ISite that supports mirrors.
+ * The regular update site contains features (optionally grouped by categories), while
+ * a mirrored site can define zero or more updates sites (mirrors) with the same content.
+ * This allows users to pick their own update site, for performance purposes.
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface ISiteWithMirrors extends ISite {
+
+ /**
+ * Returns an array of mirror sites that contain the same features/plugins.
+ * @return array of mirror sites, or empty array
+ * @throws CoreException
+ * @since 3.1
+ */
+ IURLEntry[] getMirrorSiteEntries() throws CoreException;
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IURLEntry.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IURLEntry.java
new file mode 100644
index 0000000..93ebf0f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IURLEntry.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+
+/**
+ * URL entry is an annotated URL object. It allows descriptive text to be
+ * associated with a URL. When used as description object, the annotation
+ * typically corresponds to short descriptive text, with the URL reference
+ * pointing to full browsable description.
+ * <p>
+ * Clients may implement this interface. However, in most cases clients should
+ * directly instantiate or subclass the provided implementation of this
+ * interface.
+ * </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>
+ * @see org.eclipse.update.core.URLEntry
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IURLEntry extends IAdaptable {
+
+ public static final int UPDATE_SITE = 0;
+ public static final int WEB_SITE = 1;
+
+ /**
+ * Returns the URL annotation or <code>null</code> if none
+ *
+ * @return url annotation or <code>null</code> if none
+ * @since 2.0
+ */
+ public String getAnnotation();
+
+ /**
+ * Returns the actual URL.
+ *
+ * @return url.
+ * @since 2.0
+ */
+ public URL getURL();
+
+ /**
+ * Returns the type of the URLEntry
+ *
+ * @see #UPDATE_SITE
+ * @see #WEB_SITE
+ * @return type
+ * @since 2.0
+ */
+ public int getType();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IUpdateConstants.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IUpdateConstants.java
new file mode 100644
index 0000000..c4a1381
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IUpdateConstants.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+
+/**
+ * Manages a list of static constants.
+ *
+ * <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>
+ * @since 2.0.2
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IUpdateConstants {
+
+ /**
+ * No matching rule specified
+ * @since 2.0
+ */
+ public static final int RULE_NONE = 0;
+
+ /**
+ * Dependency can be satisfied only with plug-in version matching
+ * exactly the specified version.
+ * @since 2.0
+ */
+ public static final int RULE_PERFECT = 1;
+
+ /**
+ * Dependency can be satisfied only with plug-in version that is
+ * equivalent to the specified version (same major and minor version
+ * identifier, greater than or equal service identifier).
+ * @since 2.0
+ */
+ public static final int RULE_EQUIVALENT = 2;
+
+ /**
+ * Dependency can be satisfied only with plug-in version that is
+ * compatible with the specified version (either is equivalent,
+ * or greater minor identifier (but same major identifier)).
+ * @since 2.0
+ */
+ public static final int RULE_COMPATIBLE = 3;
+
+ /**
+ * Dependency can be satisfied only with plug-in version that is
+ * greater or equal to the specified version.
+ * @since 2.0
+ */
+ public static final int RULE_GREATER_OR_EQUAL = 4;
+
+ /**
+ * Dependency can be satisfied only if the required identifier
+ * is a prefix of the specified identifier.
+ * @since 2.1
+ */
+ public static final int RULE_PREFIX = 1;
+
+ /**
+ * The search location for updates is defined by the root feature.
+ * @since 2.0.2
+ */
+ public static final int SEARCH_ROOT = 1<<1;
+
+ /**
+ * The search location for updates is defined by this feature.
+ * @since 2.0.2
+ */
+ public static final int SEARCH_SELF = 1<<2;
+
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IVerificationListener.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IVerificationListener.java
new file mode 100644
index 0000000..16ac847
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IVerificationListener.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+/**
+ * Verification listener. This interface abstract the user interaction
+ * that may be required as a result of feature installation. In particular,
+ * as feature archives are downloaded and verified, the user may need to
+ * indicate whether to accept any one of the archives, or abort the
+ * installation.
+ * <p>
+ * Clients may implement this interface.
+ * </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>
+ * @see org.eclipse.update.core.IVerificationResult
+ * @see org.eclipse.update.core.IVerifier
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IVerificationListener {
+
+ /**
+ * Indicate the action that resulted in this notification should be aborted.
+ *
+ * @since 2.0
+ */
+ public static final int CHOICE_ABORT = 0;
+
+ /**
+ * Indicate there was an error in processing the request.
+ * The action that resulted in this notification should be aborted.
+ *
+ * @since 2.0
+ */
+ public static final int CHOICE_ERROR = 1;
+
+ /**
+ * Indicate that the target of the verification should be accepted,
+ * but the information supplied with the verification result
+ * should be trusted only for this request.
+ *
+ * @since 2.0
+ */
+ public static final int CHOICE_INSTALL_TRUST_ONCE = 2;
+
+ /**
+ * Indicate that the target of the verification should be accepted,
+ * and the information supplied with the verification result
+ * should be trusted for this request, and subsequent requests.
+ *
+ * @since 2.0
+ */
+ public static final int CHOICE_INSTALL_TRUST_ALWAYS = 3;
+
+ /**
+ * Determine if we should continue with the current action
+ * based on the indicated verification results. Typically,
+ * the implementation of this method will prompt the user
+ * for the appropriate answer. However, other respose
+ * implementations can be provided.
+ *
+ * @param result verification result
+ * @since 2.0
+ */
+ public int prompt(IVerificationResult result);
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IVerificationResult.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IVerificationResult.java
new file mode 100644
index 0000000..8ceacc5
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IVerificationResult.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+/**
+ * Verification result. An object implementing this interface represents
+ * a token passed between the update framework and the verifier and verification
+ * listener. The verifier uses the token to capture the result of the file
+ * verification. It is then passed to the verification listener
+ * to optionally present this information to the user (in an
+ * implementation-specific way). The verification listener in turn
+ * uses this token to capture the desired response.
+ * <p>
+ * Clients may implement this interface.
+ * </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>
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IVerificationResult {
+
+ /**
+ * Indicates the file type is recognized but the file is not signed
+ *
+ * @see #TYPE_ENTRY_UNRECOGNIZED
+ * @since 2.0
+ */
+ public static final int TYPE_ENTRY_NOT_SIGNED = 1;
+
+ /**
+ * Indicates the file has been modified since it was signed
+ *
+ * @since 2.0
+ */
+ public static final int TYPE_ENTRY_CORRUPTED = 2;
+
+ /**
+ * Indicates the file is signed by a known signer
+ *
+ * @since 2.0
+ */
+ public static final int TYPE_ENTRY_SIGNED_RECOGNIZED = 3;
+
+ /**
+ * Indicates the file is signed but the signer is not known
+ *
+ * @since 2.0
+ */
+ public static final int TYPE_ENTRY_SIGNED_UNRECOGNIZED = 5;
+
+ /**
+ * Error occurred during verification
+ *
+ * @since 2.0
+ */
+ public static final int UNKNOWN_ERROR = 6;
+
+ /**
+ * Verification was cancelled
+ *
+ * @since 2.0
+ */
+ public static final int VERIFICATION_CANCELLED = 7;
+
+ /**
+ * Could not perform verification due to unrecognized file
+ *
+ * @see #TYPE_ENTRY_NOT_SIGNED
+ * @since 2.0
+ */
+ public static final int TYPE_ENTRY_UNRECOGNIZED = 8;
+
+ /**
+ * Returns the content reference that is the target of the verification.
+ *
+ * @return content reference
+ * @since 2.0
+ */
+ public ContentReference getContentReference();
+
+ /**
+ * Returns the feature the referenced file is part of.
+ *
+ * @return feature
+ * @since 2.0
+ */
+ public IFeature getFeature();
+
+ /**
+ * Returns the verification code.
+ *
+ * @return verification code, as defined in this interface.
+ * @since 2.0
+ */
+ public int getVerificationCode();
+
+ /**
+ * Returns any exception caught during verification
+ *
+ * @return exception, or <code>null</code>.
+ * @since 2.0
+ */
+ public Exception getVerificationException();
+
+ /**
+ * Returns display text describing the result of the verification.
+ *
+ * @return result text, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getText();
+
+ /**
+ * Returns text describing the signer
+ *
+ * @return signer information, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getSignerInfo();
+
+ /**
+ * Returns text describing the authority that verified/ certified
+ * the signer
+ *
+ * @return verifier information, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getVerifierInfo();
+
+ /**
+ * Indicates whether the referenced file is part of the overall feature
+ * definition, or one of its component plug-in or non-plug-in entries.
+ *
+ * @return <code>true</code> if reference is a feature file,
+ * <code>false</code> if reference is a plug-in or non-plug-in file
+ * @since 2.0
+ */
+ public boolean isFeatureVerification();
+
+ /**
+ * Indicates whether the signer and verifier info have already been accepted by the user
+ * during a previous verification of one of the file of the feature.
+ *
+ * @return <code>true</code> if the result has already been accepted, <code>false</code>
+ * if the result has not yet been accepted by the user
+ * @since 2.0
+ */
+ public boolean alreadySeen();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IVerifier.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IVerifier.java
new file mode 100644
index 0000000..61d835a
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IVerifier.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.*;
+
+/**
+ * Verifier. This interface abstracts the archive verification step
+ * performed by specific feature implementations. The actual details
+ * of the verification are the responsibility of the concrete implementation.
+ * <p>
+ * Clients may implement this interface.
+ * </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>
+ * @see org.eclipse.update.core.IVerificationResult
+ * @see org.eclipse.update.core.IFeatureContentProvider#getVerifier()
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IVerifier {
+
+ /**
+ * Perform verification of the specified archive.
+ *
+ * @param feature feature containing this archive
+ * @param reference actual archive reference
+ * @param isFeatureVerification <code>true</code> indicates the specified
+ * reference should be considered as part of the feature description
+ * information (ie. verifying the overall feature),
+ * <code>false</code> indicates the specified reference is a plug-in
+ * or a non-plug-in archive file (ie. verifying a component of the
+ * feature)
+ * @param monitor progress monitor, can be <code>null</code>
+ * @return verification result
+ * @exception CoreException
+ * @since 2.0
+ */
+ public IVerificationResult verify(
+ IFeature feature,
+ ContentReference reference,
+ boolean isFeatureVerification,
+ InstallMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Sets the parent verifier.
+ *
+ * The parent verifier can only be set once by the parent feature.
+ * It may used for different verification strategies.
+ * (for instance, you may decide that both the parent and current verifier
+ * must sucessfully verify the content reference, or that only one of them must verify)
+ * @param parentVerifier the parent verifier.
+ */
+ public void setParent(IVerifier parentVerifier);
+
+ /**
+ * Returns the parent verifier
+ *
+ * @return the parent verifier
+ * @since 2.0
+ */
+ public IVerifier getParent();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/Import.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/Import.java
new file mode 100644
index 0000000..156b006
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/Import.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.update.core.model.ImportModel;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+
+/**
+ * Convenience implementation of a plug-in dependency.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.IImport
+ * @see org.eclipse.update.core.model.ImportModel
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class Import extends ImportModel implements IImport {
+
+ //PERF: new instance variable
+ private VersionedIdentifier versionId;
+
+ /**
+ * Returns an identifier of the dependent plug-in.
+ * @see IImport#getVersionedIdentifier()
+ */
+ public VersionedIdentifier getVersionedIdentifier() {
+ if (versionId != null)
+ return versionId;
+
+ String id = getIdentifier();
+ String ver = getVersion();
+ if (id != null && ver != null) {
+ try {
+ versionId = new VersionedIdentifier(id, ver);
+ return versionId;
+ } catch (Exception e) {
+ UpdateCore.warn("Unable to create versioned identifier:" + id + ":" + ver); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+
+ versionId = new VersionedIdentifier("",null); //$NON-NLS-1$
+ return versionId;
+ }
+
+ /**
+ * Returns the matching rule for the dependency.
+ * @see IImport#getRule()
+ */
+ public int getRule() {
+ return UpdateManagerUtils.getMatchingRule(getMatchingRuleName());
+ }
+
+ /**
+ * Returns the matching rule for the dependency identifier.
+ * @see IImport#getIdRule()
+ */
+ public int getIdRule() {
+ return UpdateManagerUtils.getMatchingIdRule(getMatchingIdRuleName());
+ }
+
+ /**
+ *
+ * @see org.eclipse.update.core.IImport#getKind()
+ */
+
+ /**
+ * Returns the dependency kind
+ * @see org.eclipse.update.core.IImport#getKind()
+ */
+ public int getKind() {
+ return isFeatureImport()?KIND_FEATURE:KIND_PLUGIN;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/IncludedFeatureReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/IncludedFeatureReference.java
new file mode 100644
index 0000000..7b8ee28
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/IncludedFeatureReference.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * James D Miles (IBM Corp.) - bug 182625, Missing constructor
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.core.model.IncludedFeatureReferenceModel;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+
+/**
+ * This is a utility class representing the options of a nested feature.
+ * Feature will include other features. This class will represent the options of the inclusion.
+ * <p>
+ * Clients may instantiate; not intended to be subclassed 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>
+ * @see org.eclipse.update.core.VersionedIdentifier
+ * @since 2.0.1
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class IncludedFeatureReference
+ extends IncludedFeatureReferenceModel
+ implements IIncludedFeatureReference {
+
+ /**
+ * Construct a included feature reference
+ *
+ * @since 2.1
+ */
+ public IncludedFeatureReference() {
+ super();
+ }
+
+ /**
+ * Construct a feature options
+ *
+ * @param includedFeatureRef reference to clone
+ * @since 2.0.2
+ */
+ public IncludedFeatureReference(IIncludedFeatureReference includedFeatureRef) {
+ super((IncludedFeatureReferenceModel) includedFeatureRef);
+ }
+
+ /**
+ * Constructor IncludedFeatureReference.
+ * @param featureReference
+ */
+ public IncludedFeatureReference(IFeatureReference featureReference) {
+ super(featureReference);
+ }
+
+ public IncludedFeatureReference(IncludedFeatureReferenceModel includedFeatureRefModel){
+ super(includedFeatureRefModel);
+ }
+
+ /*
+ * Method isDisabled.
+ * @return boolean
+ */
+ private boolean isDisabled() {
+ IConfiguredSite cSite = getSite().getCurrentConfiguredSite();
+ if (cSite == null)
+ return false;
+ IFeatureReference[] configured = cSite.getConfiguredFeatures();
+ for (int i = 0; i < configured.length; i++) {
+ if (this.equals(configured[i]))
+ return false;
+ }
+ return true;
+ // // FIXME: the above code was commented out and returned false.
+ // // Should this be commented out again?
+ // return false;
+ }
+
+ /*
+ * Method isInstalled.
+ * @return boolean
+ */
+ private boolean isUninstalled() {
+ if (!isDisabled())
+ return false;
+ IFeatureReference[] installed = getSite().getFeatureReferences();
+ for (int i = 0; i < installed.length; i++) {
+ if (this.equals(installed[i]))
+ return false;
+ }
+ // if we reached this point, the configured site exists and it does not
+ // contain this feature reference, so clearly the feature is uninstalled
+ return true;
+ }
+
+ /**
+ * @see org.eclipse.update.core.IIncludedFeatureReference#getFeature(boolean,
+ * IConfiguredSite)
+ * @deprecated use getFeature(IProgressMonitor)
+ */
+ public IFeature getFeature(
+ boolean perfectMatch,
+ IConfiguredSite configuredSite)
+ throws CoreException {
+ return getFeature(null);
+ }
+
+ /**
+ * @see org.eclipse.update.core.IIncludedFeatureReference#getFeature(boolean,
+ * IConfiguredSite,IProgressMonitor)
+ * @deprecated use getFeature(IProgressMonitor)
+ */
+ public IFeature getFeature(
+ boolean perfectMatch,
+ IConfiguredSite configuredSite,
+ IProgressMonitor monitor)
+ throws CoreException {
+ return getFeature(monitor);
+ }
+
+ /**
+ * @see org.eclipse.update.core.IFeatureReference#getFeature()
+ * @deprecated use getFeature(IProgressMonitor)
+ */
+ public IFeature getFeature() throws CoreException {
+ return getFeature(null);
+ }
+ /**
+ * @see org.eclipse.update.core.IFeatureReference#getFeature
+ * (IProgressMonitor)
+ */
+ public IFeature getFeature(IProgressMonitor monitor) throws CoreException {
+ if (isUninstalled())
+ throw new CoreException(new Status(IStatus.ERROR, UpdateCore.getPlugin().getBundle().getSymbolicName(), IStatus.OK, NLS.bind(Messages.IncludedFeatureReference_featureUninstalled, (new String[] { getFeatureIdentifier() })), null));
+ else
+ return super.getFeature(monitor);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/InstallHandlerEntry.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/InstallHandlerEntry.java
new file mode 100644
index 0000000..900254b
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/InstallHandlerEntry.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.update.core.model.InstallHandlerEntryModel;
+
+/**
+ * Convenience implementation of an install handler entry.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.IInstallHandlerEntry
+ * @see org.eclipse.update.core.model.InstallHandlerEntryModel
+ * @see org.eclipse.update.core.IInstallHandler
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class InstallHandlerEntry
+ extends InstallHandlerEntryModel
+ implements IInstallHandlerEntry {
+
+ /**
+ * Constructor for InstallHandlerEntry.
+ * @since 2.0
+ */
+ public InstallHandlerEntry() {
+ super();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/InstallMonitor.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/InstallMonitor.java
new file mode 100644
index 0000000..b722575
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/InstallMonitor.java
@@ -0,0 +1,279 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.util.Stack;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.internal.core.Messages;
+
+/**
+ * Install progress monitor
+ * Delegating wrapper for IProgressMonitor used for installation handling.
+ *
+ * <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>
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class InstallMonitor implements IProgressMonitor {
+
+ protected IProgressMonitor monitor;
+ protected Stack tasks;
+
+ protected String taskString;
+ protected String subTaskString;
+ protected boolean showDetails;
+ protected long totalCopyCount;
+ protected long currentCount = 0;
+
+ protected class MonitorState {
+
+ private String taskString;
+ private String subTaskString;
+ private boolean showDetails;
+ private long totalCopyCount;
+ private long currentCount;
+
+ private MonitorState(
+ String taskString,
+ String subTaskString,
+ boolean showDetails,
+ long currentCount,
+ long totalCopyCount) {
+ this.taskString = taskString;
+ this.subTaskString = subTaskString;
+ this.showDetails = showDetails;
+ this.currentCount = currentCount;
+ this.totalCopyCount = totalCopyCount;
+ }
+
+ private String getTaskString() {
+ return this.taskString;
+ }
+
+ private String getSubTaskString() {
+ return this.subTaskString;
+ }
+
+ private boolean getShowDetails() {
+ return this.showDetails;
+ }
+
+ private long getCurrentCount() {
+ return this.currentCount;
+ }
+
+ private long getTotalCopyCount() {
+ return this.totalCopyCount;
+ }
+ }
+
+ protected InstallMonitor() {
+ }
+
+ /**
+ * Install monitor constructor
+ *
+ * @param monitor base install monitor
+ * @since 2.0
+ */
+ public InstallMonitor(IProgressMonitor monitor) {
+ this.monitor = monitor;
+ this.tasks = new Stack();
+ this.taskString = ""; //$NON-NLS-1$
+ this.subTaskString = ""; //$NON-NLS-1$
+ this.showDetails = false;
+ this.totalCopyCount = 0;
+ }
+
+ /**
+ * Begin new monitor task.
+ *
+ * @see IProgressMonitor#beginTask(String, int)
+ * @since 2.0
+ */
+ public void beginTask(String name, int totalWork) {
+ taskString = name;
+ monitor.beginTask(name, totalWork);
+ }
+
+ /**
+ * Indicate completion of monitor activity.
+ *
+ * @see IProgressMonitor#done()
+ * @since 2.0
+ */
+ public void done() {
+ monitor.done();
+ }
+
+ /**
+ * Indicate monitor progress.
+ *
+ * @see IProgressMonitor#internalWorked(double)
+ * @since 2.0
+ */
+ public void internalWorked(double work) {
+ monitor.internalWorked(work);
+ }
+
+ /**
+ * Check is use indicated that the operation be cancelled.
+ *
+ * @see IProgressMonitor#isCanceled()
+ * @since 2.0
+ */
+ public boolean isCanceled() {
+ return monitor.isCanceled();
+ }
+
+ /**
+ * Set the cancellation state.
+ *
+ * @see IProgressMonitor#setCanceled(boolean)
+ * @since 2.0
+ */
+ public void setCanceled(boolean value) {
+ monitor.setCanceled(value);
+ }
+
+ /**
+ * Set task name.
+ *
+ * @see IProgressMonitor#setTaskName(String)
+ * @since 2.0
+ */
+ public void setTaskName(String name) {
+ this.taskString = name;
+ this.subTaskString = ""; //$NON-NLS-1$
+ this.showDetails = false;
+ this.totalCopyCount = 0;
+ monitor.subTask(""); //$NON-NLS-1$
+ monitor.setTaskName(name);
+ }
+
+ /**
+ * Set subtask name.
+ *
+ * @see IProgressMonitor#subTask(String)
+ * @since 2.0
+ */
+ public void subTask(String name) {
+ this.subTaskString = name;
+ this.showDetails = false;
+ this.totalCopyCount = 0;
+ monitor.subTask(name);
+ }
+
+ /**
+ * Indicate monitor progress.
+ *
+ * @see IProgressMonitor#worked(int)
+ * @since 2.0
+ */
+ public void worked(int work) {
+ monitor.worked(work);
+ }
+
+ /**
+ * Save the current monitor state.
+ * The states are saved on a push-down stack. Prior states
+ * can be restored by calling restorState()
+ *
+ * @see #restoreState()
+ * @since 2.0
+ */
+ public void saveState() {
+ tasks.push(
+ new MonitorState(taskString, subTaskString, showDetails, currentCount, totalCopyCount));
+ }
+
+ /**
+ * Restore the monitor state.
+ *
+ * @see #saveState()
+ * @since 2.0
+ */
+ public void restoreState() {
+ if (tasks.size() > 0) {
+ MonitorState state = (MonitorState) tasks.pop();
+ setTaskName(state.getTaskString());
+ subTask(state.getSubTaskString());
+ this.showDetails = state.getShowDetails();
+ this.currentCount = state.getCurrentCount();
+ this.totalCopyCount = state.getTotalCopyCount();
+ }
+ }
+
+ /**
+ * Indicate whether the monitor subtask message should include
+ * copy progress counts.
+ *
+ * @see #setCopyCount(long)
+ * @see #setTotalCount(long)
+ * @param setting <code>true</code> to show the copy count,
+ * <code>false</code> otherwise
+ * @since 2.0
+ */
+ public void showCopyDetails(boolean setting) {
+ this.showDetails = setting;
+ }
+
+ /**
+ * Sets the total number of bytes to copy.
+ *
+ * @see #showCopyDetails(boolean)
+ * @see #setCopyCount(long)
+ * @param count total number of bytes to copy.
+ * @since 2.0
+ */
+ public void setTotalCount(long count) {
+ this.totalCopyCount = count;
+ }
+
+ /**
+ * Sets the number of bytes already copied.
+ *
+ * @see #showCopyDetails(boolean)
+ * @see #setTotalCount(long)
+ * @param count number of bytes already copied.
+ * @since 2.0
+ */
+ public void setCopyCount(long count) {
+ if (showDetails && count > 0) {
+ currentCount = count;
+ long countK = count / 1024;
+ long totalK = totalCopyCount / 1024;
+ String msg =
+ (totalK <= 0)
+ ? NLS.bind(Messages.InstallMonitor_DownloadSize, (new String[] { Long.toString(countK) }))
+ : NLS.bind(Messages.InstallMonitor_DownloadSizeLong, (new String[] { Long.toString(countK), Long.toString(totalK) }));
+ monitor.subTask(subTaskString + msg);
+ }
+ }
+
+ /**
+ * Increments the number of bytes copied.
+ *
+ * @param increment number of new bytes copied.
+ * @since 3.0
+ */
+ public void incrementCount(long increment) {
+ setCopyCount(currentCount + increment);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/JarContentReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/JarContentReference.java
new file mode 100644
index 0000000..1ea7f3a
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/JarContentReference.java
@@ -0,0 +1,370 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.io.*;
+import java.net.*;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.*;
+
+import org.eclipse.update.core.model.*;
+import org.eclipse.update.internal.core.*;
+
+/**
+ * Local .jar file content reference.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.ContentReference
+ * @see org.eclipse.update.core.JarEntryContentReference
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class JarContentReference extends ContentReference {
+
+ //private static ArrayList referenceList = new ArrayList();
+ private JarFile jarFile;
+
+ /**
+ * Content selector used in .jar operations.
+ * Default implementation causes all file entries to be selected with
+ * generated identifiers being the same as the original .jar entry name.
+ *
+ * @since 2.0
+ */
+ public static class ContentSelector {
+
+ /**
+ * Indicates whether the .jar entry should be selected.
+ * Default behavior is to select all non-directory entries.
+ *
+ * @param entry .jar entry
+ * @return <code>true</code> if entry is to be selected,
+ * <code>false</code> otherwise
+ * @since 2.0
+ */
+ public boolean include(JarEntry entry) {
+ return entry == null ? false : !entry.isDirectory();
+ }
+
+ /**
+ * Defines the "symbolic" path identifier for the
+ * entry. Default identifier is the same as the jar entry name.
+ *
+ * @param entry .jar entry
+ * @return "symbolic" path identifier
+ * @since 2.0
+ */
+ public String defineIdentifier(JarEntry entry) {
+ return entry == null ? null : entry.getName();
+ }
+ }
+
+ /**
+ * Create jar content reference from URL.
+ *
+ * @param id "symbolic" path identifier
+ * @param url actual referenced URL
+ * @since 2.0
+ */
+ public JarContentReference(String id, URL url) {
+ super(id, url);
+ this.jarFile = null;
+ //referenceList.add(this); // keep track of archives
+ }
+
+ /**
+ * Create jar content reference from file.
+ *
+ * @param id "symbolic" path identifier
+ * @param file actual referenced file
+ * @since 2.0
+ */
+ public JarContentReference(String id, File file) {
+ super(id, file);
+ this.jarFile = null;
+ //referenceList.add(this); // keep track of archives
+ }
+
+ /**
+ * A factory method to create a jar content reference.
+ *
+ * @param id "symbolic" path identifier
+ * @param file actual referenced file
+ * @return jar content reference
+ * @since 2.0
+ */
+ public ContentReference createContentReference(String id, File file) {
+ return new JarContentReference(id, file,true);
+ }
+ /**
+ * Constructor JarContentReference.
+ * @param id
+ * @param file
+ * @param b
+ */
+ public JarContentReference(String id, File file, boolean b) {
+ this(id,file);
+ setTempLocal(b);
+ }
+
+ /**
+ * Returns the content reference as a jar file. Note, that this method
+ * <b>does not</b> cause the file to be downloaded if it
+ * is not already local.
+ *
+ * @return reference as jar file
+ * @exception IOException reference cannot be returned as jar file
+ * @since 2.0
+ */
+ protected JarFile asJarFile() throws IOException {
+ if (this.jarFile == null) {
+ File file = asFile();
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL)
+ UpdateCore.debug("asJarFile :" + file); //$NON-NLS-1$
+ if (file != null && !file.exists()) {
+ UpdateCore.warn("JarFile does not exits:" + file); //$NON-NLS-1$
+ throw new FileNotFoundException(file.getAbsolutePath());
+ }
+ this.jarFile = new JarFile(file);
+ }
+ return jarFile;
+ }
+
+ /**
+ * Unpacks the referenced jar archive into the specified location.
+ * Returns content references to the unpacked files.
+ *
+ * @param dir location to unpack the jar into
+ * @param selector selector, used to select entries to unpack, and to define
+ * "symbolic" path identifiers for the entries.
+ * @param monitor progress monitor
+ * @exception IOException
+ * @exception InstallAbortedException
+ * @since 2.0
+ */
+ public ContentReference[] unpack(File dir, ContentSelector selector, InstallMonitor monitor) throws IOException, InstallAbortedException {
+
+ // make sure we have a selector
+ if (selector == null)
+ selector = new ContentSelector();
+
+ // get archive content
+ JarFile jarArchive = this.asJarFile();
+ List content = new ArrayList();
+ Enumeration entries = jarArchive.entries();
+
+ // run through the entries and unjar
+ String entryId;
+ JarEntry entry;
+ InputStream is;
+ OutputStream os;
+ File localFile;
+ try {
+ if (monitor != null) {
+ monitor.saveState();
+ monitor.setTaskName(Messages.JarContentReference_Unpacking);
+ monitor.subTask(this.getIdentifier());
+ monitor.showCopyDetails(false);
+ }
+ while (entries.hasMoreElements()) {
+ entry = (JarEntry) entries.nextElement();
+ if (entry != null && selector.include(entry)) {
+ is = null;
+ os = null;
+ entryId = selector.defineIdentifier(entry);
+ localFile = Utilities.createLocalFile(dir, entryId); // create temp file
+ if (!entry.isDirectory()) {
+ try {
+ is = jarArchive.getInputStream(entry);
+ os = new FileOutputStream(localFile);
+ Utilities.copy(is, os, monitor);
+ } finally {
+ if (is != null)
+ try {
+ is.close();
+ } catch (IOException e) {
+ }
+ if (os != null)
+ try {
+ os.close();
+ } catch (IOException e) {
+ }
+ }
+ content.add(new ContentReference(entryId, localFile));
+ }
+ }
+ }
+ } finally {
+ if (monitor != null)
+ monitor.restoreState();
+ }
+ return (ContentReference[]) content.toArray(new ContentReference[0]);
+ }
+
+ /**
+ * Unpacks the named jar entry into the specified location.
+ * Returns content reference to the unpacked file.
+ *
+ * @param dir location to unpack the jar into
+ * @param entryName name of the jar entry
+ * @param selector selector, used to define "symbolic" path identifier
+ * for the entry
+ * @param monitor progress monitor
+ * @exception IOException
+ * @exception InstallAbortedException
+ * @since 2.0
+ */
+ public ContentReference unpack(File dir, String entryName, ContentSelector selector, InstallMonitor monitor) throws IOException, InstallAbortedException {
+
+ // make sure we have a selector
+ if (selector == null)
+ selector = new ContentSelector();
+
+ // unjar the entry
+ JarFile jarArchive = this.asJarFile();
+ entryName = entryName.replace(File.separatorChar, '/');
+ JarEntry entry = jarArchive.getJarEntry(entryName);
+ String entryId;
+ if (entry != null) {
+ InputStream is = null;
+ OutputStream os = null;
+ entryId = selector.defineIdentifier(entry);
+ File localFile = Utilities.createLocalFile(dir, entryId); // create temp file
+ if (!entry.isDirectory()) {
+ try {
+ is = jarArchive.getInputStream(entry);
+ os = new FileOutputStream(localFile);
+ Utilities.copy(is, os, monitor);
+ } finally {
+ if (is != null)
+ try {
+ is.close();
+ } catch (IOException e) {
+ }
+ if (os != null)
+ try {
+ os.close();
+ } catch (IOException e) {
+ }
+ }
+ return new ContentReference(entryId, localFile);
+ } else
+ return null; // entry was a directory
+ } else
+ throw new FileNotFoundException(this.asFile().getAbsolutePath() + " " + entryName); //$NON-NLS-1$
+ }
+
+ /**
+ * Peeks into the referenced jar archive.
+ * Returns content references to the jar entries within the jar file.
+ *
+ * @param selector selector, used to select entries to return, and to define
+ * "symbolic" path identifiers for the entries.
+ * @param monitor progress monitor
+ * @exception IOException
+ * @since 2.0
+ */
+ public ContentReference[] peek(ContentSelector selector, InstallMonitor monitor) throws IOException {
+
+ // make sure we have a selector
+ if (selector == null)
+ selector = new ContentSelector();
+
+ // get archive content
+ JarFile jarArchive = this.asJarFile();
+ List content = new ArrayList();
+ Enumeration entries = jarArchive.entries();
+
+ // run through the entries and create content references
+ JarEntry entry;
+ String entryId;
+ while (entries.hasMoreElements()) {
+ entry = (JarEntry) entries.nextElement();
+ if (selector.include(entry)) {
+ entryId = selector.defineIdentifier(entry);
+ content.add(new JarEntryContentReference(entryId, this, entry));
+ }
+ }
+ return (ContentReference[]) content.toArray(new ContentReference[0]);
+ }
+
+ /**
+ * Peeks into the referenced jar archive looking for the named entry.
+ * Returns content reference to the jar entry within the jar file.
+ *
+ * @param entryName name of the jar entry
+ * @param selector selector, used to define "symbolic" path identifier
+ * for the entry
+ * @param monitor progress monitor
+ * @return the content reference ofr <code>null</null> if the entry doesn't exist
+ * @exception IOException
+ * @since 2.0
+ */
+ public ContentReference peek(String entryName, ContentSelector selector, InstallMonitor monitor) throws IOException {
+
+ // make sure we have a selector
+ if (selector == null)
+ selector = new ContentSelector();
+
+ // assume we have a reference that represents a jar archive.
+ JarFile jarArchive = this.asJarFile();
+ entryName = entryName.replace(File.separatorChar, '/');
+ JarEntry entry = jarArchive.getJarEntry(entryName);
+ if (entry == null)
+ return null;
+
+ String entryId = selector.defineIdentifier(entry);
+ return new JarEntryContentReference(entryId, this, entry);
+ }
+
+ /**
+ * Closes the jar archive corresponding to this reference.
+ *
+ * @exception IOException
+ * @since 2.0
+ */
+ public void closeArchive() throws IOException {
+ if (this.jarFile != null) {
+ this.jarFile.close();
+ this.jarFile = null;
+ }
+ }
+
+ /**
+ * Perform shutdown processing for jar archive handling.
+ * This method is called when platform is shutting down.
+ * It is not intended to be called at any other time under
+ * normal circumstances. A side-effect of calling this method
+ * is that all jars referenced by JarContentReferences are closed.
+ *
+ * @since 2.0
+ */
+ public static void shutdown() {
+ /*for (int i = 0; i < referenceList.size(); i++) {
+ JarContentReference ref = (JarContentReference) referenceList.get(i);
+ try {
+ ref.closeArchive(); // ensure we are not leaving open jars
+ } catch (IOException e) {
+ // we tried, nothing we can do ...
+ }
+ }*/
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/JarEntryContentReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/JarEntryContentReference.java
new file mode 100644
index 0000000..336532c
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/JarEntryContentReference.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.io.*;
+import java.net.*;
+import java.util.jar.*;
+
+/**
+ * .jar file entry content reference.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.ContentReference
+ * @see org.eclipse.update.core.JarContentReference
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class JarEntryContentReference extends ContentReference {
+
+ private JarContentReference jarContentReference;
+ private JarEntry entry;
+
+ /**
+ * Create jar entry content reference.
+ *
+ * @param id "symbolic" path identifier
+ * @param jarContentReference jar file content reference
+ * @param entry jar entry
+ * @since 2.0
+ */
+ public JarEntryContentReference(
+ String id,
+ JarContentReference jarContentReference,
+ JarEntry entry) {
+ super(id, (File) null);
+ this.jarContentReference = jarContentReference;
+ this.entry = entry;
+ }
+
+ /**
+ * Creates an input stream for the reference.
+ *
+ * @return input stream
+ * @exception IOException unable to create stream
+ * @since 2.0
+ */
+ public InputStream getInputStream() throws IOException {
+ return jarContentReference.asJarFile().getInputStream(entry);
+ }
+
+ /**
+ * Returns the size of the referenced entry.
+ *
+ * @return input size
+ * @since 2.0
+ */
+ public long getInputSize() {
+ return entry.getSize();
+ }
+
+ /**
+ * Indicates whether the reference is to a an entry within a local jar.
+ *
+ * @return <code>true</code> if the reference is local,
+ * otherwise <code>false</code>
+ * @since 2.0
+ */
+ public boolean isLocalReference() {
+ return jarContentReference.isLocalReference();
+ }
+
+ /**
+ * Returns the content reference as a URL.
+ *
+ * @return reference as URL
+ * @exception IOException reference cannot be returned as URL
+ * @since 2.0
+ */
+ public URL asURL() throws IOException {
+ String fileName =
+ jarContentReference.asFile().getAbsolutePath().replace(File.separatorChar, '/');
+ return new URL("jar:file:" + fileName + "!/" + entry.getName()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Return string representation of this reference.
+ *
+ * @return string representation
+ * @since 2.0
+ */
+ public String toString() {
+ URL url;
+ try {
+ url = asURL();
+ } catch (IOException e) {
+ url = null;
+ }
+ if (url != null)
+ return url.toExternalForm();
+ else
+ return getClass().getName() + "@" + hashCode(); //$NON-NLS-1$
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/NonPluginEntry.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/NonPluginEntry.java
new file mode 100644
index 0000000..f854de1
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/NonPluginEntry.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.update.core.model.*;
+
+/**
+ * Convenience implementation of non-plug-in entry.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.INonPluginEntry
+ * @see org.eclipse.update.core.model.NonPluginEntryModel
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class NonPluginEntry
+ extends NonPluginEntryModel
+ implements INonPluginEntry {
+
+ /**
+ * Non-plug-in entry default constructor
+ */
+ public NonPluginEntry() {
+ super();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/PluginEntry.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/PluginEntry.java
new file mode 100644
index 0000000..3a92eb9
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/PluginEntry.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.update.core.model.*;
+import org.eclipse.update.internal.core.*;
+
+/**
+ * Convenience implementation of plug-in entry.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.IPluginEntry
+ * @see org.eclipse.update.core.model.PluginEntryModel
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class PluginEntry extends PluginEntryModel implements IPluginEntry {
+
+ // PERF: new instance variable
+ private VersionedIdentifier versionId;
+
+ /**
+ * Plug-in entry default constructor
+ */
+ public PluginEntry() {
+ super();
+ }
+
+ /**
+ * Returns the identifier of this plugin entry
+ *
+ * @see IPluginEntry#getVersionedIdentifier()
+ * @since 2.0
+ */
+ public VersionedIdentifier getVersionedIdentifier() {
+ if (versionId != null)
+ return versionId;
+
+ String id = getPluginIdentifier();
+ String ver = getPluginVersion();
+ if (id != null && ver != null) {
+ try {
+ versionId = new VersionedIdentifier(id, ver);
+ return versionId;
+ } catch (Exception e) {
+ UpdateCore.warn("Unable to create versioned identifier:" + id + ":" + ver); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ versionId = new VersionedIdentifier("",null); //$NON-NLS-1$
+ return versionId;
+ }
+
+ /**
+ * Sets the identifier of this plugin entry.
+ *
+ * @see IPluginEntry#setVersionedIdentifier(VersionedIdentifier)
+ * @since 2.0
+ */
+ public void setVersionedIdentifier(VersionedIdentifier identifier) {
+ setPluginIdentifier(identifier.getIdentifier());
+ setPluginVersion(identifier.getVersion().toString());
+ }
+
+ /**
+ * Compares two plugin entries for equality
+ *
+ * @param object plugin entry object to compare with
+ * @return <code>true</code> if the two entries are equal,
+ * <code>false</code> otherwise
+ * @since 2.0
+ */
+ public boolean equals(Object object) {
+ if (!(object instanceof IPluginEntry))
+ return false;
+ IPluginEntry e = (IPluginEntry) object;
+ return getVersionedIdentifier().equals(e.getVersionedIdentifier());
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/Site.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/Site.java
new file mode 100644
index 0000000..2c6b211
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/Site.java
@@ -0,0 +1,562 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * James D Miles (IBM Corp.) - bug 191783, NullPointerException in FeatureDownloader
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.model.*;
+import org.eclipse.update.internal.core.*;
+
+/**
+ * Convenience implementation of a site.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.ISite
+ * @see org.eclipse.update.core.model.SiteModel
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class Site extends SiteModel implements ISiteWithMirrors {
+
+ /**
+ * Default installation path for features
+ *
+ * @since 2.0
+ */
+ public static final String DEFAULT_INSTALLED_FEATURE_PATH = "features/"; //$NON-NLS-1$
+
+ /**
+ * Default installation path for plug-ins and plug-in fragments
+ *
+ * @since 2.0
+ */
+ public static final String DEFAULT_PLUGIN_PATH = "plugins/"; //$NON-NLS-1$
+
+ /**
+ * Default path on a site where packaged features are located
+ *
+ * @since 2.0
+ */
+ public static final String DEFAULT_FEATURE_PATH = "features/"; //$NON-NLS-1$
+
+ /**
+ * Default site manifest file name
+ *
+ * @since 2.0
+ */
+ public static final String SITE_FILE = "site"; //$NON-NLS-1$
+
+ /**
+ * Default site manifest extension
+ *
+ * @since 2.0
+ */
+ public static final String SITE_XML = SITE_FILE + ".xml"; //$NON-NLS-1$
+
+ private ISiteContentProvider siteContentProvider;
+
+ private Map featureCache = Collections.synchronizedMap(new HashMap()); // key=URLKey value=IFeature
+
+ /**
+ * Constructor for Site
+ */
+ public Site() {
+ super();
+ }
+
+ /**
+ * Compares two sites for equality
+ *
+ * @param obj site object to compare with
+ * @return <code>true</code> if the two sites are equal,
+ * <code>false</code> otherwise
+ * @since 2.0
+ */
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ISite))
+ return false;
+ if (getURL() == null)
+ return false;
+ ISite otherSite = (ISite) obj;
+
+ return UpdateManagerUtils.sameURL(getURL(), otherSite.getURL());
+ }
+
+ /**
+ * Returns the site URL
+ *
+ * @see ISite#getURL()
+ * @since 2.0
+ */
+ public URL getURL() {
+ URL url = null;
+ try {
+ url = getSiteContentProvider().getURL();
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ }
+ return url;
+ }
+
+ /**
+ * Returns the site description.
+ *
+ * @see ISite#getDescription()
+ * @since 2.0
+ */
+ public IURLEntry getDescription() {
+ return (IURLEntry) getDescriptionModel();
+ }
+
+ /**
+ * Returns an array of categories defined by the site.
+ *
+ * @see ISite#getCategories()
+ * @since 2.0
+ */
+ public ICategory[] getCategories() {
+ CategoryModel[] result = getCategoryModels();
+ if (result.length == 0)
+ return new ICategory[0];
+ else
+ return (ICategory[]) result;
+ }
+
+ /**
+ * Returns the named site category.
+ *
+ * @see ISite#getCategory(String)
+ * @since 2.0
+ */
+ public ICategory getCategory(String key) {
+ ICategory result = null;
+ boolean found = false;
+ int length = getCategoryModels().length;
+
+ for (int i = 0; i < length; i++) {
+ if (getCategoryModels()[i].getName().equals(key)) {
+ result = (ICategory) getCategoryModels()[i];
+ found = true;
+ break;
+ }
+ }
+
+ //DEBUG:
+ if (!found) {
+ String URLString = (this.getURL() != null) ? this.getURL().toExternalForm() : "<no site url>"; //$NON-NLS-1$
+ UpdateCore.warn(NLS.bind(Messages.Site_CannotFindCategory, (new String[] { key, URLString })));
+ if (getCategoryModels().length <= 0)
+ UpdateCore.warn(Messages.Site_NoCategories);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns an array of references to features on this site.
+ *
+ * @see ISite#getFeatureReferences()
+ * @since 2.0
+ */
+ public ISiteFeatureReference[] getRawFeatureReferences() {
+ FeatureReferenceModel[] result = getFeatureReferenceModels();
+ if (result.length == 0)
+ return new ISiteFeatureReference[0];
+ else
+ return (ISiteFeatureReference[]) result;
+ }
+
+ /**
+ * @see org.eclipse.update.core.ISite#getFeatureReferences()
+ */
+ public ISiteFeatureReference[] getFeatureReferences() {
+ // only filter local site
+ if (getCurrentConfiguredSite()!=null)
+ return filterFeatures(getRawFeatureReferences());
+ else
+ return getRawFeatureReferences();
+
+ }
+
+ /*
+ * Method filterFeatures.
+ * Also implemented in Feature
+ *
+ * @param list
+ * @return List
+ */
+ private ISiteFeatureReference[] filterFeatures(ISiteFeatureReference[] allIncluded) {
+ List list = new ArrayList();
+ if (allIncluded!=null){
+ for (int i = 0; i < allIncluded.length; i++) {
+ ISiteFeatureReference included = allIncluded[i];
+ if (UpdateManagerUtils.isValidEnvironment(included))
+ list.add(included);
+ else{
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_WARNINGS){
+ UpdateCore.warn("Filtered out feature reference:"+included); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ ISiteFeatureReference[] result = new ISiteFeatureReference[list.size()];
+ if (!list.isEmpty()){
+ list.toArray(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a reference to the specified feature on this site.
+ *
+ * @see ISite#getFeatureReference(IFeature)
+ * @since 2.0
+ */
+ public ISiteFeatureReference getFeatureReference(IFeature feature) {
+
+ if (feature == null) {
+ UpdateCore.warn("Site:getFeatureReference: The feature is null"); //$NON-NLS-1$
+ return null;
+ }
+
+ ISiteFeatureReference[] references = getFeatureReferences();
+ ISiteFeatureReference currentReference = null;
+ for (int i = 0; i < references.length; i++) {
+ currentReference = references[i];
+ //if (UpdateManagerUtils.sameURL(feature.getURL(), currentReference.getURL()))
+ // return currentReference;
+ try {
+ if (feature.getVersionedIdentifier().equals(currentReference.getVersionedIdentifier()))
+ return currentReference;
+ } catch (CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ UpdateCore.warn("Feature " + feature + " not found on site" + this.getURL()); //$NON-NLS-1$ //$NON-NLS-2$
+ return null;
+ }
+
+ /**
+ * Returns an array of plug-in and non-plug-in archives located
+ * on this site
+ *
+ * @see ISite#getArchives()
+ * @since 2.0
+ */
+ public IArchiveReference[] getArchives() {
+ ArchiveReferenceModel[] result = getArchiveReferenceModels();
+ if (result.length == 0)
+ return new IArchiveReference[0];
+ else
+ return (IArchiveReference[]) result;
+ }
+
+ /**
+ * Returns the content provider for this site.
+ *
+ * @see ISite#getSiteContentProvider()
+ * @since 2.0
+ */
+ public ISiteContentProvider getSiteContentProvider() throws CoreException {
+ if (siteContentProvider == null) {
+ throw Utilities.newCoreException(Messages.Site_NoContentProvider, null);
+ }
+ return siteContentProvider;
+ }
+
+ /**
+ * Returns the default type for a packaged feature supported by this site
+ *
+ * @see ISite#getDefaultPackagedFeatureType()
+ * @since 2.0
+ */
+ public String getDefaultPackagedFeatureType() {
+ return DEFAULT_PACKAGED_FEATURE_TYPE;
+ }
+
+ /**
+ * Returns an array of entries corresponding to plug-ins installed
+ * on this site.
+ *
+ * @see ISite#getPluginEntries()
+ * @since 2.0
+ */
+ public IPluginEntry[] getPluginEntries() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns the number of plug-ins installed on this site
+ *
+ * @see ISite#getPluginEntryCount()
+ * @since 2.0
+ */
+ public int getPluginEntryCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns an array of entries corresponding to plug-ins that are
+ * installed on this site and are referenced only by the specified
+ * feature.
+ *
+ * @see ISite#getPluginEntriesOnlyReferencedBy(IFeature) *
+ * @since 2.0
+ */
+ public IPluginEntry[] getPluginEntriesOnlyReferencedBy(IFeature feature) throws CoreException {
+
+ IPluginEntry[] pluginsToRemove = new IPluginEntry[0];
+ if (feature == null)
+ return pluginsToRemove;
+
+ // get the plugins from the feature
+ IPluginEntry[] entries = feature.getPluginEntries();
+ if (entries != null) {
+ // get all the other plugins from all the other features
+ Set allPluginID = new HashSet();
+ ISiteFeatureReference[] features = getFeatureReferences();
+ if (features != null) {
+ for (int indexFeatures = 0; indexFeatures < features.length; indexFeatures++) {
+ IFeature featureToCompare = null;
+ try {
+ featureToCompare = features[indexFeatures].getFeature(null);
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ }
+ if (!feature.equals(featureToCompare)) {
+ IPluginEntry[] pluginEntries = features[indexFeatures].getFeature(null).getPluginEntries();
+ if (pluginEntries != null) {
+ for (int indexEntries = 0; indexEntries < pluginEntries.length; indexEntries++) {
+ allPluginID.add(pluginEntries[indexEntries].getVersionedIdentifier());
+ }
+ }
+ }
+ }
+ }
+
+ // create the delta with the plugins that may be still used by other configured or unconfigured feature
+ List plugins = new ArrayList();
+ for (int indexPlugins = 0; indexPlugins < entries.length; indexPlugins++) {
+ if (!allPluginID.contains(entries[indexPlugins].getVersionedIdentifier())) {
+ plugins.add(entries[indexPlugins]);
+ }
+ }
+
+ // move List into Array
+ if (!plugins.isEmpty()) {
+ pluginsToRemove = new IPluginEntry[plugins.size()];
+ plugins.toArray(pluginsToRemove);
+ }
+ }
+
+ return pluginsToRemove;
+ }
+
+ /**
+ * Adds a new plug-in entry to this site.
+ * This implementation always throws UnsupportedOperationException
+ * because this implementation does not support the install action.
+ *
+ * @see ISite#addPluginEntry(IPluginEntry)
+ * @exception java.lang.UnsupportedOperationException
+ * @since 2.0
+ */
+ public void addPluginEntry(IPluginEntry pluginEntry) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get download size for the specified feature on this site.
+ * This implementation always throws UnsupportedOperationException
+ * because this implementation does not support the install action.
+ *
+ * @see ISite#getDownloadSizeFor(IFeature)
+ * @exception java.lang.UnsupportedOperationException
+ * @since 2.0
+ */
+ public long getDownloadSizeFor(IFeature feature) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get install size for the specified feature on this site.
+ * This implementation always throws UnsupportedOperationException
+ * because this implementation does not support the install action.
+ *
+ * @see ISite#getInstallSizeFor(IFeature)
+ * @exception java.lang.UnsupportedOperationException
+ * @since 2.0
+ */
+ public long getInstallSizeFor(IFeature feature) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Install the specified feature and all optional features on this site.
+ * This implementation always throws UnsupportedOperationException
+ * because this implementation does not support the install action.
+ *
+ * @see ISite#install(IFeature, IVerificationListener, IProgressMonitor)
+ * @exception InstallAbortedException when the user cancels the install
+ * @exception CoreException
+ * @exception java.lang.UnsupportedOperationException
+ * @since 2.0
+ */
+ public IFeatureReference install(IFeature sourceFeature, IVerificationListener verificationListener, IProgressMonitor progress) throws InstallAbortedException, CoreException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Install the specified feature and listed optional features on this site.
+ * This implementation always throws UnsupportedOperationException
+ * because this implementation does not support the install action.
+ *
+ * @see ISite#install(IFeature, IVerificationListener, IProgressMonitor)
+ * @exception InstallAbortedException when the user cancels the install
+ * @exception CoreException
+ * @exception java.lang.UnsupportedOperationException
+ * @since 2.0
+ */
+ public IFeatureReference install(IFeature sourceFeature, IFeatureReference[] optionalFeatures, IVerificationListener verificationListener, IProgressMonitor progress) throws InstallAbortedException, CoreException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Install the specified feature on this site using the content consumer as
+ * a context to install the feature in.
+ * This implementation always throws UnsupportedOperationException
+ * because this implementation does not support the install action.
+ *
+ * @param sourceFeature feature to install
+ * @param parentContentConsumer content consumer of the parent feature
+ * @param parentVerifier verifier of the parent feature
+ * @param verificationListener install verification listener
+ * @param progress install monitor, can be <code>null</code>
+ * @exception InstallAbortedException when the user cancels the install
+ * @exception CoreException
+ * @exception java.lang.UnsupportedOperationException
+ * @since 2.0
+ */
+ public IFeatureReference install(IFeature sourceFeature, IFeatureReference[] optionalFeatures, IFeatureContentConsumer parentContentConsumer, IVerifier parentVerifier, IVerificationListener verificationListener, IProgressMonitor progress)
+ throws CoreException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Remove (uninstall) the specified feature from this site.
+ * This implementation always throws UnsupportedOperationException
+ * because this implementation does not support the remove action.
+ *
+ * @see ISite#remove(IFeature, IProgressMonitor)
+ * @exception java.lang.UnsupportedOperationException
+ * @since 2.0
+ */
+ public void remove(IFeature feature, IProgressMonitor progress) throws CoreException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Sets the site content provider.
+ *
+ * @see ISite#setSiteContentProvider(ISiteContentProvider)
+ * @since 2.0
+ */
+ public void setSiteContentProvider(ISiteContentProvider siteContentProvider) {
+ this.siteContentProvider = siteContentProvider;
+ }
+ /**
+ * @see ISite#getCurrentConfiguredSite()
+ */
+ public IConfiguredSite getCurrentConfiguredSite() {
+ return (IConfiguredSite) getConfiguredSiteModel();
+ }
+
+ /**
+ * @see org.eclipse.update.core.ISite#createFeature(String, URL)
+ * @deprecated
+ */
+ public IFeature createFeature(String type, URL url) throws CoreException {
+ return createFeature(type,url,null);
+ }
+
+ /**
+ * @see org.eclipse.update.core.ISite#createFeature(String, URL,
+ * IProgressMonitor)
+ */
+ public IFeature createFeature(String type, URL url, IProgressMonitor monitor) throws CoreException {
+
+ if(url == null) {
+ UpdateCore.warn("The feature URL passed is null");
+ return null;
+ }
+
+ // First check the cache
+ URLKey key = new URLKey(url);
+ IFeature feature = (IFeature) featureCache.get(key);
+ if (feature != null) return feature;
+
+ // Create a new one
+ if (type == null || type.equals("")) { //$NON-NLS-1$
+ // ask the Site for the default type
+ type = getDefaultPackagedFeatureType();
+ }
+
+ IFeatureFactory factory = FeatureTypeFactory.getInstance().getFactory(type);
+ feature = factory.createFeature(url, this, monitor);
+ if (feature != null) {
+ // Add the feature to the cache
+ featureCache.put(key, feature);
+ }
+ return feature;
+ }
+
+ protected void removeFeatureFromCache(URL featureURL) {
+ URLKey key = new URLKey(featureURL);
+ featureCache.remove(key);
+ }
+
+ /**
+ * Return an array of mirror update sites.
+ *
+ * @return an array of mirror update sites
+ * @since 2.0
+ */
+ public IURLEntry[] getMirrorSiteEntries() {
+ URLEntryModel[] result = getMirrorSiteEntryModels();
+ if (result.length == 0)
+ return new IURLEntry[0];
+ else
+ return (IURLEntry[]) result;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/SiteContentProvider.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/SiteContentProvider.java
new file mode 100644
index 0000000..8f38779
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/SiteContentProvider.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+
+/**
+ * Base site content provider
+ * <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>
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public abstract class SiteContentProvider implements ISiteContentProvider {
+
+ private URL base;
+ private ISite site;
+
+ /**
+ * Constructor for SiteContentProvider
+ */
+ public SiteContentProvider(URL url) {
+ super();
+ this.base = url;
+ }
+
+ /**
+ * Returns the URL of this site
+ *
+ * @see ISiteContentProvider#getURL()
+ * @since 2.0
+ */
+ public URL getURL() {
+ return base;
+ }
+
+ /**
+ * Returns a URL for the identified archive
+ *
+ * @see ISiteContentProvider#getArchiveReference(String)
+ * @since 2.0
+ */
+ private URL getArchiveReference1(String archiveID) throws CoreException {
+ try {
+ return new URL(getURL(), archiveID);
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.SiteContentProvider_ErrorCreatingURLForArchiveID, (new String[] { archiveID, getURL().toExternalForm() })),
+ e);
+ }
+ }
+
+ /**
+ * Returns the site for this provider
+ *
+ * @see ISiteContentProvider#getSite()
+ * @since 2.0
+ */
+ public ISite getSite() {
+ return site;
+ }
+
+ /**
+ * Sets the site for this provider
+ *
+ * @param site site for this provider
+ * @since 2.0
+ */
+ public void setSite(ISite site) {
+ this.site = site;
+ }
+
+ public URL getArchiveReference(String archiveId) throws CoreException {
+ URL contentURL = null;
+
+ contentURL = getArchiveURLfor(archiveId);
+ // if there is no mapping in the site.xml
+ // for this archiveId, use the default one
+ if (contentURL==null) {
+ return getArchiveReference1(archiveId);
+ }
+
+ return contentURL;
+ }
+
+ /**
+ * return the URL associated with the id of teh archive for this site
+ * return null if the archiveId is null, empty or
+ * if teh list of archives on the site is null or empty
+ * of if there is no URL associated with the archiveID for this site
+ */
+ private URL getArchiveURLfor(String archiveId) {
+ URL result = null;
+ boolean found = false;
+
+ IArchiveReference[] siteArchives = getSite().getArchives();
+ if (siteArchives.length > 0) {
+ for (int i = 0; i < siteArchives.length && !found; i++) {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL)
+ UpdateCore.debug("GetArchiveURL for:"+archiveId+" compare to "+siteArchives[i].getPath()); //$NON-NLS-1$ //$NON-NLS-2$
+ if (archiveId.trim().equalsIgnoreCase(siteArchives[i].getPath())) {
+ result = siteArchives[i].getURL();
+ found = true;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/SiteFeatureReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/SiteFeatureReference.java
new file mode 100644
index 0000000..7876b03
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/SiteFeatureReference.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+
+/**
+ * Convenience implementation of a feature reference.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.IFeatureReference
+ * @see org.eclipse.update.core.model.FeatureReferenceModel
+ * @see org.eclipse.update.core.ISiteFeatureReference
+ * @see org.eclipse.update.core.SiteFeatureReferenceModel
+ * @since 2.1
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class SiteFeatureReference extends SiteFeatureReferenceModel implements ISiteFeatureReference {
+
+ private List categories;
+
+ /**
+ * Feature reference default constructor
+ */
+ public SiteFeatureReference() {
+ super();
+ }
+
+ /**
+ * Constructor FeatureReference.
+ * @param ref the reference to copy
+ */
+ public SiteFeatureReference(ISiteFeatureReference ref) {
+ super(ref);
+ }
+
+ /**
+ * Returns an array of categories the referenced feature belong to.
+ *
+ * @see ISiteFeatureReference#getCategories()
+ * @since 2.1
+ */
+ public ICategory[] getCategories() {
+
+ if (categories == null) {
+ categories = new ArrayList();
+ String[] categoriesAsString = getCategoryNames();
+ for (int i = 0; i < categoriesAsString.length; i++) {
+ ICategory siteCat = getSite().getCategory(categoriesAsString[i]);
+ if (siteCat != null)
+ categories.add(siteCat);
+ else {
+ String siteURL = getSite().getURL() != null ? getSite().getURL().toExternalForm() : null;
+ UpdateCore.warn("Category " + categoriesAsString[i] + " not found in Site:" + siteURL); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ }
+
+ if (categories.size() == 0) {
+ //there was no category defined
+ //so we add the default "Other" category
+ ICategory category = new Category(Messages.SiteCategory_other_label, Messages.SiteCategory_other_description);
+ categories.add(category);
+ }
+
+ ICategory[] result = new ICategory[0];
+
+ if (!(categories == null || categories.isEmpty())) {
+ result = new ICategory[categories.size()];
+ categories.toArray(result);
+ }
+ return result;
+ }
+
+ /**
+ * Adds a category to the referenced feature.
+ *
+ * @see ISiteFeatureReference#addCategory(ICategory)
+ * @since 2.1
+ */
+ public void addCategory(ICategory category) {
+ this.addCategoryName(category.getName());
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/SiteFeatureReferenceModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/SiteFeatureReferenceModel.java
new file mode 100644
index 0000000..671c69e
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/SiteFeatureReferenceModel.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Site Feature reference model object.
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead instantiate or subclass the provided
+ * concrete implementation of this model.
+ * </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>
+ * @see org.eclipse.update.core.FeatureReference
+ * @since 2.1
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class SiteFeatureReferenceModel extends FeatureReference {
+
+ private List /* of String*/
+ categoryNames;
+
+
+ /**
+ * Creates an uninitialized feature reference model object.
+ *
+ * @since 2.0
+ */
+ public SiteFeatureReferenceModel() {
+ super();
+ }
+
+ /**
+ * Constructor FeatureReferenceModel.
+ * @param ref
+ */
+ public SiteFeatureReferenceModel(ISiteFeatureReference ref) {
+ super(ref);
+ if (ref instanceof SiteFeatureReferenceModel) {
+ SiteFeatureReferenceModel refModel = (SiteFeatureReferenceModel) ref;
+ setCategoryNames(refModel.getCategoryNames());
+ }
+ }
+
+
+ /**
+ * Returns the names of categories the referenced feature belongs to.
+ *
+ * @return an array of names, or an empty array.
+ * @since 2.0
+ */
+ public String[] getCategoryNames() {
+ if (categoryNames == null)
+ return new String[0];
+
+ return (String[]) categoryNames.toArray(new String[0]);
+ }
+
+ /**
+ * Sets the names of categories this feature belongs to.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param categoryNames an array of category names
+ * @since 2.0
+ */
+ public void setCategoryNames(String[] categoryNames) {
+ assertIsWriteable();
+ if (categoryNames == null)
+ this.categoryNames = null;
+ else
+ this.categoryNames = new ArrayList(Arrays.asList(categoryNames));
+ }
+
+ /**
+ * Adds the name of a category this feature belongs to.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param categoryName category name
+ * @since 2.0
+ */
+ public void addCategoryName(String categoryName) {
+ assertIsWriteable();
+ if (this.categoryNames == null)
+ this.categoryNames = new ArrayList();
+ if (!this.categoryNames.contains(categoryName))
+ this.categoryNames.add(categoryName);
+ }
+
+ /**
+ * Removes the name of a categorys this feature belongs to.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param categoryName category name
+ * @since 2.0
+ */
+ public void removeCategoryName(String categoryName) {
+ assertIsWriteable();
+ if (this.categoryNames != null)
+ this.categoryNames.remove(categoryName);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/SiteManager.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/SiteManager.java
new file mode 100644
index 0000000..8aeebcf
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/SiteManager.java
@@ -0,0 +1,342 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Laurent Fourrier (laurent@fourrier.nom.fr) - HTTP Proxy code and NetAccess Plugin
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.net.URL;
+
+import org.eclipse.core.net.proxy.IProxyData;
+import org.eclipse.core.net.proxy.IProxyService;
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.ILocalSite;
+import org.eclipse.update.internal.core.InternalSiteManager;
+import org.eclipse.update.internal.core.UpdateCore;
+
+/**
+ * Site Manager.
+ * A helper class used for creating site instance.
+ * Site manager is a singleton class. It cannot be instantiated;
+ * all functionality is provided by static methods.
+ *
+ * <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>
+ * @see org.eclipse.update.core.ISite
+ * @see org.eclipse.update.configuration.ILocalSite
+ * @see org.eclipse.update.configuration.IConfiguredSite
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class SiteManager {
+
+ private static String os;
+ private static String ws;
+ private static String arch;
+ private static String nl;
+
+ private SiteManager() {
+ }
+
+ /**
+ * Returns a site object for the site specified by the argument URL.
+ * Typically, the URL references a site manifest file on an update
+ * site. An update site acts as a source of features for installation
+ * actions.
+ *
+ * @param siteURL site URL
+ * @return site object for the url
+ * @exception CoreException
+ * @deprecated use getSite(URL,IPogressMonitor) instead
+ * @since 2.0
+ */
+ public static ISite getSite(URL siteURL) throws CoreException {
+ return InternalSiteManager.getSite(siteURL, true,null);
+ }
+
+ /**
+ * Returns a site object for the site specified by the argument URL.
+ * Typically, the URL references a site manifest file on an update
+ * site. An update site acts as a source of features for installation
+ * actions.
+ *
+ * @param siteURL site URL
+ * @param monitor the progress monitor
+ * @return site object for the url or <samp>null</samp> in case a
+ * user canceled the connection in the progress monitor.
+ * @exception CoreException
+ * @since 2.1
+ */
+ public static ISite getSite(URL siteURL, IProgressMonitor monitor) throws CoreException {
+ return InternalSiteManager.getSite(siteURL, true, monitor);
+ }
+
+ /**
+ * Returns a site object for the site specified by the argument URL.
+ * Typically, the URL references a site manifest file on an update
+ * site. An update site acts as a source of features for installation
+ * actions.
+ *
+ * @param siteURL site URL
+ * @param usesCache <code>false</code> if the cache should be refreshed, and the site entirely reparsed, <code>false</code> otherwise.
+ * @return site object for the url
+ * @exception CoreException
+ * @deprecated use getSite(URL,boolean,IPogressMonitor) instead
+ * @since 2.0
+ */
+ public static ISite getSite(URL siteURL, boolean usesCache) throws CoreException {
+ return InternalSiteManager.getSite(siteURL, usesCache,null);
+ }
+
+ /**
+ * Returns a site object for the site specified by the argument URL.
+ * Typically, the URL references a site manifest file on an update
+ * site. An update site acts as a source of features for installation
+ * actions.
+ *
+ * @param siteURL site URL
+ * @param usesCache <code>false</code> if the cache should be refreshed, and the site entirely reparsed, <code>false</code> otherwise.
+ * @param monitor the progress monitor
+ * @return site object for the url or <samp>null</samp> in case a
+ * user canceled the connection in the progress monitor.
+ * @exception CoreException
+ * @since 2.1
+ */
+ public static ISite getSite(URL siteURL, boolean usesCache, IProgressMonitor monitor) throws CoreException {
+ return InternalSiteManager.getSite(siteURL, usesCache, monitor);
+ }
+
+
+ /**
+ * Returns the "local site". A local site is a logical collection
+ * of configuration information plus one or more file system
+ * installation directories, represented as intividual sites.
+ * These are potential targets for installation actions.
+ *
+ * @return the local site
+ * @exception CoreException
+ * @since 2.0
+ */
+ public static ILocalSite getLocalSite() throws CoreException {
+ return InternalSiteManager.getLocalSite();
+ }
+
+ /**
+ * Trigger handling of newly discovered features. This method
+ * can be called by the executing application whenever it
+ * is invoked with the -newUpdates command line argument.
+ *
+ * @throws CoreException if an error occurs.
+ * @since 2.0
+ * @deprecated Do not use this method
+ */
+ public static void handleNewChanges() throws CoreException {
+ }
+ /**
+ * Returns system architecture specification. A comma-separated list of arch
+ * designators defined by the platform.
+ *
+ * This information is used as a hint by the installation and update
+ * support.
+ *
+ * @return system architecture specification
+ * @since 2.1
+ */
+ public static String getOSArch() {
+ if (arch == null)
+ arch = Platform.getOSArch();
+ return arch;
+ }
+
+ /**
+ * Returns operating system specification. A comma-separated list of os
+ * designators defined by the platform.
+ *
+ * This information is used as a hint by the installation and update
+ * support.
+ *
+ * @return the operating system specification.
+ * @since 2.1
+ */
+ public static String getOS() {
+ if (os == null)
+ os = Platform.getOS();
+ return os;
+ }
+
+ /**
+ * Returns system architecture specification. A comma-separated list of arch
+ * designators defined by the platform.
+ *
+ * This information is used as a hint by the installation and update
+ * support.
+ * @return system architecture specification.
+ * @since 2.1
+ */
+ public static String getWS() {
+ if (ws == null)
+ ws = Platform.getWS();
+ return ws;
+ }
+
+ /**
+ * Sets the arch.
+ * @param arch The arch to set
+ */
+ public static void setOSArch(String arch) {
+ SiteManager.arch = arch;
+ }
+
+ /**
+ * Sets the os.
+ * @param os The os to set
+ */
+ public static void setOS(String os) {
+ SiteManager.os = os;
+ }
+
+ /**
+ * Sets the ws.
+ * @param ws The ws to set
+ */
+ public static void setWS(String ws) {
+ SiteManager.ws = ws;
+ }
+
+ /**
+ * Sets the nl.
+ * @param nl The nl to set
+ */
+ public static void setNL(String nl) {
+ SiteManager.nl = nl;
+ }
+
+ /**
+ * Returns an estimate of bytes per second transfer rate for this URL
+ * @param site the URL of the site
+ * @return long a bytes per second estimate rate
+ * @since 2.1
+ */
+ public static long getEstimatedTransferRate(URL site) {
+ if (site == null)
+ return 0;
+ return InternalSiteManager.getEstimatedTransferRate(site.getHost());
+ }
+
+ /**
+ * Returns current locale
+ *
+ * @return the string name of the current locale or <code>null</code>
+ * @since 2.1
+ */
+ public static String getNL() {
+ if (nl == null)
+ nl = Platform.getNL();
+ return nl;
+ }
+
+ /**
+ * Returns the HTTP Proxy Server or <code>null</code> if none.
+ * @return the HTTP proxy Server
+ * @deprecated clients should access the {@link IProxyService} directly
+ */
+ public static String getHttpProxyServer() {
+ IProxyService service = UpdateCore.getPlugin().getProxyService();
+ if (service != null && service.isProxiesEnabled()) {
+ IProxyData data = service.getProxyData(IProxyData.HTTP_PROXY_TYPE);
+ if (data != null)
+ return data.getHost();
+
+ }
+ return null;
+ }
+ /**
+ * Returns the HTTP Proxy Port or <code>null</code> if none
+ * @return the HTTP proxy Port
+ * @deprecated clients should access the {@link IProxyService} directly
+ */
+ public static String getHttpProxyPort() {
+ IProxyService service = UpdateCore.getPlugin().getProxyService();
+ if (service != null && service.isProxiesEnabled()) {
+ IProxyData data = service.getProxyData(IProxyData.HTTP_PROXY_TYPE);
+ if (data != null) {
+ if (data.getPort() == -1)
+ return "80";
+ return String.valueOf(data.getPort());
+ }
+
+ }
+ return null;
+ }
+
+ /**
+ * Returns <code>true</code> if the connection should use the
+ * http proxy server, <code>false</code> otherwise
+ * @return is the http proxy server enable
+ * @deprecated clients should access the {@link IProxyService} directly
+ */
+ public static boolean isHttpProxyEnable() {
+ IProxyService service = UpdateCore.getPlugin().getProxyService();
+ if (service != null && service.isProxiesEnabled()) {
+ IProxyData data = service.getProxyData(IProxyData.HTTP_PROXY_TYPE);
+ return (data != null && data.getHost() != null);
+ }
+ return false;
+ }
+ /**
+ * Sets the HTTP Proxy information
+ * Sets the HTTP proxy server for the HTTP proxy server
+ * Sets the HTTP proxy port for the HTTP proxy server
+ * If the proxy name is <code>null</code> or the proxy port is
+ * <code>null</code> the connection will not use HTTP proxy server.
+ *
+ * @param enable <code>true</code> if the connection should use an http
+ * proxy server, <code>false </code> otherwise.
+ * @param httpProxyServer the HTTP proxy server name or IP address
+ * @param httpProxyPort the HTTP proxy port
+ *
+ * @deprecated clients should use the {@link IProxyService} directly
+ */
+ public static void setHttpProxyInfo(boolean enable, String httpProxyServer, String httpProxyPort) {
+ IProxyService service = UpdateCore.getPlugin().getProxyService();
+ if (service == null)
+ return;
+ // Make sure that the proxy service is enabled if needed but don't disable the
+ // service if the http proxy is being disabled
+ if (enable && !service.isProxiesEnabled())
+ service.setProxiesEnabled(enable);
+
+ if (service.isProxiesEnabled()) {
+ IProxyData data = service.getProxyData(IProxyData.HTTP_PROXY_TYPE);
+ if (data != null) {
+ data.setHost(httpProxyServer);
+ if (httpProxyPort == null || httpProxyPort.equals("80")) {
+ data.setPort(-1);
+ } else {
+ try {
+ int port = Integer.parseInt(httpProxyPort);
+ data.setPort(port);
+ } catch (NumberFormatException e) {
+ UpdateCore.log(e);
+ }
+ }
+ try {
+ service.setProxyData(new IProxyData[] { data });
+ } catch (CoreException e) {
+ UpdateCore.log(e);
+ }
+ }
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/URLEntry.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/URLEntry.java
new file mode 100644
index 0000000..21342b7
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/URLEntry.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.update.core.model.*;
+import org.eclipse.update.internal.core.*;
+
+/**
+ * Convenience implementation of an annotated URL.
+ * <p>
+ * This class may be instantiated or subclassed 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>
+ * @see org.eclipse.update.core.IURLEntry
+ * @see org.eclipse.update.core.model.URLEntryModel
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class URLEntry extends URLEntryModel implements IURLEntry {
+
+ /**
+ * Default constructor for annotated URL
+ *
+ * @since 2.0
+ */
+ public URLEntry() {
+ super();
+ }
+
+ /**
+ * Returns a string representation of an annotated URL.
+ *
+ * @return annotated url as String
+ * @since 2.0
+ */
+ public String toString() {
+ String result = "IURLEntry: "; //$NON-NLS-1$
+ String URLString =
+ (getURL() == null) ? Messages.Feature_NoURL : getURL().toExternalForm();
+ result =
+ result
+ + ((getAnnotation() == null) ? URLString : getAnnotation() + " : " + URLString); //$NON-NLS-1$
+ return result;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/Utilities.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/Utilities.java
new file mode 100644
index 0000000..ccde29f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/Utilities.java
@@ -0,0 +1,353 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import java.io.*;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.model.*;
+import org.eclipse.update.internal.core.*;
+
+/**
+ * This class is a collection of utility functions that can be
+ * used for install processing
+ * <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>
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class Utilities {
+
+ private static Map entryMap;
+ private static final DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.getDefault());
+ private static long tmpseed = (new Date()).getTime();
+ private static String dirRoot = null;
+
+ /**
+ * Returns a new working directory (in temporary space). Ensures
+ * the directory exists. Any directory levels that had to be created
+ * are marked for deletion on exit.
+ *
+ * @return working directory
+ * @exception IOException
+ * @since 2.0
+ */
+ public static synchronized File createWorkingDirectory() throws IOException {
+
+ if (dirRoot == null) {
+ dirRoot = System.getProperty("java.io.tmpdir"); //$NON-NLS-1$
+ // in Linux, returns '/tmp', we must add '/'
+ if (!dirRoot.endsWith(File.separator))
+ dirRoot += File.separator;
+
+ // on Unix/Linux, the temp dir is shared by many users, so we need to ensure
+ // that the top working directory is different for each user
+ if (!Platform.getOS().equals("win32")) { //$NON-NLS-1$
+ String home = System.getProperty("user.home"); //$NON-NLS-1$
+ home = Integer.toString(home.hashCode());
+ dirRoot += home + File.separator;
+ }
+ dirRoot += "eclipse" + File.separator + ".update" + File.separator + Long.toString(tmpseed) + File.separator; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ String tmpName = dirRoot + Long.toString(++tmpseed) + File.separator;
+
+ File tmpDir = new File(tmpName);
+ verifyPath(tmpDir, false);
+ if (!tmpDir.exists())
+ throw new FileNotFoundException(tmpName);
+ return tmpDir;
+ }
+
+ /**
+ * Create a new working file. The file is marked for deletion on exit.
+ *
+ * @see #lookupLocalFile(String)
+ * @param tmpDir directory location for new file. Any missing directory
+ * levels are created (and marked for deletion on exit)
+ * @param name optional file name, or <code>null</code>. If name is not
+ * specified, a temporary name is generated.
+ * @return created working file
+ * @exception IOException
+ * @since 2.0
+ */
+ public static synchronized File createLocalFile(File tmpDir, String name) throws IOException {
+ // create the local file
+ File temp;
+ String filePath;
+ if (name != null) {
+ // create file with specified name
+ filePath = name.replace('/', File.separatorChar);
+ if (filePath.startsWith(File.separator))
+ filePath = filePath.substring(1);
+ temp = new File(tmpDir, filePath);
+ } else {
+ // create file with temp name
+ temp = File.createTempFile("eclipse", null, tmpDir); //$NON-NLS-1$
+ }
+ temp.deleteOnExit();
+ verifyPath(temp, true);
+
+ return temp;
+ }
+
+ /**
+ * The file is associated with a lookup key.
+ * @param key optional lookup key, or <code>null</code>.
+ * @param temp the local working file
+ * @since 2.0.2
+ */
+ public synchronized static void mapLocalFile(String key, File temp) {
+ // create file association
+ if (key != null) {
+ if (entryMap == null)
+ entryMap = new HashMap();
+ entryMap.put(key, temp);
+ }
+ }
+
+ /**
+ * Returns a previously cached local file (in temporary area) matching the
+ * specified key.
+ *
+ * @param key lookup key
+ * @return cached file, or <code>null</code>.
+ * @since 2.0
+ */
+ public static synchronized File lookupLocalFile(String key) {
+ if (entryMap == null)
+ return null;
+ return (File) entryMap.get(key);
+ }
+
+ /**
+ * Flushes all the keys from the local file map.
+ * Reinitialize the cache.
+ *
+ * @since 2.1
+ */
+ public synchronized static void flushLocalFile() {
+ entryMap = null;
+ }
+
+ /**
+ * Removes the specified key from the local file map. The file is
+ * not actually deleted until VM termination.
+ *
+ * @param key lookup key
+ * @since 2.0
+ */
+ public static synchronized void removeLocalFile(String key) {
+ if (entryMap != null)
+ entryMap.remove(key);
+ }
+
+ /**
+ * Copies specified input stream to the output stream. Neither stream
+ * is closed as part of this operation.
+ *
+ * @param is input stream
+ * @param os output stream
+ * @param monitor progress monitor
+ * @exception IOException
+ * @exception InstallAbortedException
+ * @since 2.0
+ */
+ public static void copy(InputStream is, OutputStream os, InstallMonitor monitor) throws IOException, InstallAbortedException {
+ long offset = UpdateManagerUtils.copy(is, os, monitor, 0);
+ if (offset != -1) {
+ if (monitor != null && monitor.isCanceled()) {
+ String msg = Messages.Feature_InstallationCancelled;
+ throw new InstallAbortedException(msg, null);
+ } else {
+ throw new IOException();
+ }
+ }
+ }
+
+ /**
+ * Creates a CoreException from some other exception.
+ * The type of the CoreException is <code>IStatus.ERROR</code>
+ * If the exception passed as a parameter is also a CoreException,
+ * the new CoreException will contain all the status of the passed
+ * CoreException.
+ *
+ * @see IStatus#ERROR
+ * @param s exception string
+ * @param code the code reported
+ * @param e actual exception being reported
+ * @return a CoreException
+ * @since 2.0
+ */
+ public static CoreException newCoreException(String s, int code, Throwable e) {
+ String id = UpdateCore.getPlugin().getBundle().getSymbolicName();
+
+ // check the case of a multistatus
+ IStatus status;
+ if (e instanceof FeatureDownloadException)
+ return (FeatureDownloadException)e;
+ else if (e instanceof CoreException) {
+ if (s == null)
+ s = ""; //$NON-NLS-1$
+ status = new MultiStatus(id, code, s, e);
+ IStatus childrenStatus = ((CoreException) e).getStatus();
+ ((MultiStatus) status).add(childrenStatus);
+ ((MultiStatus) status).addAll(childrenStatus);
+ } else {
+ StringBuffer completeString = new StringBuffer(""); //$NON-NLS-1$
+ if (s != null)
+ completeString.append(s);
+ if (e != null) {
+ completeString.append(" ["); //$NON-NLS-1$
+ String msg = e.getLocalizedMessage();
+ completeString.append(msg!=null?msg:e.toString());
+ completeString.append("]"); //$NON-NLS-1$
+ }
+ status = new Status(IStatus.ERROR, id, code, completeString.toString(), e);
+ }
+ CoreException ce = new CoreException(status);
+
+ if ( e instanceof FatalIOException) {
+ ce = new CoreExceptionWithRootCause(status);
+ ((CoreExceptionWithRootCause)ce).setRootException(e);
+ }
+ /* for when we move to 1.5
+ if ( e instanceof CoreException) {
+ ce.initCause(e.getCause());
+ } else {
+ ce.initCause(e);
+ }
+ if (e != null)
+ ce.setStackTrace(e.getStackTrace());*/
+ return ce;
+ }
+
+ /**
+ * Creates a CoreException from some other exception.
+ * The type of the CoreException is <code>IStatus.ERROR</code>
+ * If the exception passed as a parameter is also a CoreException,
+ * the new CoreException will contain all the status of the passed
+ * CoreException.
+ *
+ * @see IStatus#ERROR
+ * @param s exception string
+ * @param e actual exception being reported
+ * @return a CoreException
+ * @since 2.0
+ */
+ public static CoreException newCoreException(String s, Throwable e) {
+ return newCoreException(s, IStatus.OK, e);
+ }
+
+ /**
+ * Creates a CoreException from two other CoreException
+ *
+ * @param s overall exception string
+ * @param s1 string for first detailed exception
+ * @param s2 string for second detailed exception
+ * @param e1 first detailed exception
+ * @param e2 second detailed exception
+ * @return a CoreException with multi-status
+ * @since 2.0
+ */
+ public static CoreException newCoreException(String s, String s1, String s2, CoreException e1, CoreException e2) {
+ String id = UpdateCore.getPlugin().getBundle().getSymbolicName();
+ if (s == null)
+ s = ""; //$NON-NLS-1$
+
+ IStatus childStatus1 = e1.getStatus();
+ IStatus childStatus2 = e2.getStatus();
+ int code = (childStatus1.getCode() == childStatus2.getCode()) ? childStatus1.getCode() : IStatus.OK;
+ MultiStatus multi = new MultiStatus(id, code, s, null);
+
+ multi.add(childStatus1);
+ multi.addAll(childStatus1);
+ multi.add(childStatus2);
+ multi.addAll(childStatus2);
+
+ return new CoreException(multi);
+ }
+
+ /**
+ * Formats a Date based on the default Locale
+ * If teh Date is <code>null</code> returns an empty String
+ *
+ * @param date the Date to format
+ * @return the formatted Date as a String
+ * @since 2.0
+ */
+ public static String format(Date date) {
+ if (date == null)
+ return ""; //$NON-NLS-1$
+ return dateFormat.format(date);
+ }
+
+ /**
+ * Perform shutdown processing for temporary file handling.
+ * This method is called when platform is shutting down.
+ * It is not intended to be called at any other time under
+ * normal circumstances. A side-effect of calling this method
+ * is that the contents of the temporary directory managed
+ * by this class are deleted.
+ *
+ * @since 2.0
+ */
+ public static void shutdown() {
+ if (dirRoot == null)
+ return;
+
+ File temp = new File(dirRoot); // temp directory root for this run
+ cleanupTemp(temp);
+ temp.delete();
+ }
+
+ private static void cleanupTemp(File root) {
+ File[] files = root.listFiles();
+ for (int i = 0; files != null && i < files.length; i++) {
+ if (files[i].isDirectory())
+ cleanupTemp(files[i]);
+ files[i].delete();
+ }
+ }
+
+ private static void verifyPath(File path, boolean isFile) {
+ // if we are expecting a file back off 1 path element
+ if (isFile) {
+ if (path.getAbsolutePath().endsWith(File.separator)) {
+ // make sure this is a file
+ path = path.getParentFile();
+ isFile = false;
+ }
+ }
+
+ // already exists ... just return
+ if (path.exists())
+ return;
+
+ // does not exist ... ensure parent exists
+ File parent = path.getParentFile();
+ verifyPath(parent, false);
+
+ // ensure directories are made. Mark files or directories for deletion
+ if (!isFile)
+ path.mkdir();
+ path.deleteOnExit();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/Verifier.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/Verifier.java
new file mode 100644
index 0000000..3692132
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/Verifier.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.*;
+
+/**
+ * Convenience implementation of a verifier.
+ * <p>
+ * This class may be subclassed 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>
+ * @see org.eclipse.update.core.IVerifier
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public abstract class Verifier implements IVerifier {
+
+ private IVerifier parent;
+
+ /**
+ * @see IVerifier#verify(IFeature, ContentReference, boolean, InstallMonitor)
+ */
+ public abstract IVerificationResult verify(
+ IFeature feature,
+ ContentReference reference,
+ boolean isFeatureVerification,
+ InstallMonitor monitor)
+ throws CoreException ;
+
+ /**
+ * @see IVerifier#verify(IFeature, ContentReference, boolean, InstallMonitor)
+ */
+ public void setParent(IVerifier parentVerifier){
+ if (this.parent==null){
+ this.parent = parentVerifier;
+ }
+ }
+
+ /**
+ * Returns the parent verifier
+ *
+ * @return the parent verifier
+ * @since 2.0
+ */
+ public IVerifier getParent(){
+ return parent;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/VersionedIdentifier.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/VersionedIdentifier.java
new file mode 100644
index 0000000..a578772
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/VersionedIdentifier.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.internal.core.*;
+
+/**
+ * Versioned Identifier. This is a utility class combining an identification
+ * string with a version.
+ * <p>
+ * Clients may instantiate; not intended to be subclassed 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>
+ * @see org.eclipse.core.runtime.PluginVersionIdentifier
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class VersionedIdentifier {
+ private String id;
+ private PluginVersionIdentifier version;
+ private static final String SEPARATOR = "_"; //$NON-NLS-1$
+
+ /**
+ * Construct a versioned identifier from an identifier and a string
+ * representation of a version
+ *
+ * @see org.eclipse.core.runtime.PluginVersionIdentifier#toString()
+ * @param id identifier string
+ * @param versionName string representation of version
+ * @since 2.0
+ */
+ public VersionedIdentifier(String id, String versionName) {
+ if (id == null || (id = id.trim()).equals("")) //$NON-NLS-1$
+ throw new IllegalArgumentException(
+ NLS.bind(Messages.VersionedIdentifier_IdOrVersionNull, (new String[] { id, versionName })));
+ this.id = id;
+ // 15707
+ if (versionName != null){
+ // if (PluginVersionIdentifier.validateVersionIdentifier(versionName).isOk())
+ try {
+ this.version = new PluginVersionIdentifier(versionName);
+ } catch (RuntimeException e){
+ UpdateCore.warn("Invalid Version:"+versionName,e); //$NON-NLS-1$
+ }
+ }
+ if (this.version==null)
+ version = new PluginVersionIdentifier(0, 0, 0);
+ }
+
+ /**
+ * Returns the identifier
+ *
+ * @return identifier
+ * @since 2.0
+ */
+ public String getIdentifier() {
+ return id;
+ }
+
+ /**
+ * Returns the version
+ *
+ * @return version
+ * @since 2.0
+ */
+ public PluginVersionIdentifier getVersion() {
+ return version;
+ }
+
+ /**
+ * Returns a string representation of the versioned identifier.
+ *
+ * @return string representation of versioned identifier. The resulting
+ * string is <id>_<version>, where <id> is the identifier and
+ * <version> is the string representation of the version
+ * @since 2.0
+ */
+ public String toString() {
+ return id.equals("") ? "" : id + SEPARATOR + version.toString(); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Compares two versioned identifiers for equality
+ *
+ * @param obj other versioned identifier to compare to
+ * @return <code>true</code> if the two objects are equal,
+ * <code>false</code> otherwise
+ * @since 2.0
+ */
+ public boolean equals(Object obj) {
+ if (!(obj instanceof VersionedIdentifier))
+ return false;
+ VersionedIdentifier vid = (VersionedIdentifier) obj;
+ if (!this.id.equals(vid.id))
+ return false;
+ return this.version.equals(vid.version);
+ }
+
+ /**
+ * Returns a computed hashcode for the versioned identifier.
+ *
+ * @return hash code
+ * @since 2.0
+ */
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/ArchiveReferenceModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/ArchiveReferenceModel.java
new file mode 100644
index 0000000..7359dec
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/ArchiveReferenceModel.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Site archive model object.
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead instantiate or subclass the provided
+ * concrete implementation of this model.
+ * </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>
+ * @see org.eclipse.update.core.ArchiveReference
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class ArchiveReferenceModel extends ModelObject {
+
+ private String path;
+ private String urlString;
+ private URL url;
+
+ /**
+ * Creates a uninitialized model object.
+ *
+ * @since 2.0
+ */
+ public ArchiveReferenceModel() {
+ super();
+ }
+
+ /**
+ * Retrieve the site archive "symbolic" path
+ *
+ * @return path, or <code>null</code>
+ * @since 2.0
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * Returns the unresolved URL string for the archive.
+ *
+ * @return url string, or <code>null</code>
+ * @since 2.0
+ */
+ public String getURLString() {
+ return urlString;
+ }
+
+ /**
+ * Returns the resolved URL for the archive.
+ *
+ * @return url, or <code>null</code>
+ * @since 2.0
+ */
+ public URL getURL() {
+ return url;
+ }
+
+ /**
+ * Sets the site archive "symbolic" path.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param path archive "symbolic" path.
+ * @since 2.0
+ */
+ public void setPath(String path) {
+ assertIsWriteable();
+ this.path = path;
+ }
+
+ /**
+ * Sets the unresolved URL string for the archive.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param urlString unresolved url string.
+ * @since 2.0
+ */
+ public void setURLString(String urlString) {
+ assertIsWriteable();
+ this.urlString = urlString;
+ this.url = null;
+ }
+
+ /**
+ * Resolve the model object.
+ * Any URL strings in the model are resolved relative to the
+ * base URL argument. Any translatable strings in the model that are
+ * specified as translation keys are localized using the supplied
+ * resource bundle.
+ *
+ * @param base URL
+ * @param bundleURL resource bundle URL
+ * @exception MalformedURLException
+ * @since 2.0
+ */
+ public void resolve(URL base,URL bundleURL)
+ throws MalformedURLException {
+ // resolve local elements
+ url = resolveURL(base, bundleURL, urlString);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/CategoryModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/CategoryModel.java
new file mode 100644
index 0000000..a99d88b
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/CategoryModel.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Comparator;
+
+import org.eclipse.update.core.Site;
+
+/**
+ * Feature category definition model object.
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead instantiate or subclass the provided
+ * concrete implementation of this model.
+ * </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>
+ * @see org.eclipse.update.core.Category
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class CategoryModel extends ModelObject {
+
+ private String name;
+ private String label;
+ private String localizedLabel;
+ private URLEntryModel description;
+ private static Comparator comp;
+
+ /**
+ * Creates an uninitialized model object.
+ *
+ * @since 2.0
+ */
+ public CategoryModel() {
+ super();
+ }
+
+ /**
+ * Retrieve the name of the category.
+ *
+ * @return category name, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Retrieve the displayable label for the category. If the model
+ * object has been resolved, the label is localized.
+ *
+ * @return displayable label, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getLabel() {
+ if (localizedLabel != null)
+ return localizedLabel;
+ else
+ return label;
+ }
+
+ /**
+ * Retrieve the non-localized displayable label for the category.
+ *
+ * @return non-localized displayable label, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getLabelNonLocalized() {
+ return label;
+ }
+
+ /**
+ * Retrieve the detailed category description
+ *
+ * @return category description, or <code>null</code>.
+ * @since 2.0
+ */
+ public URLEntryModel getDescriptionModel() {
+ return description;
+ }
+
+ /**
+ * Sets the category displayable label.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param label displayable label, or resource key
+ * @since 2.0
+ */
+ public void setLabel(String label) {
+ assertIsWriteable();
+ this.label = label;
+ this.localizedLabel = null;
+ }
+
+ /**
+ * Sets the category name.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param name category name
+ * @since 2.0
+ */
+ public void setName(String name) {
+ assertIsWriteable();
+ this.name = name;
+ }
+
+ /**
+ * Sets the category description.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param description category description
+ * @since 2.0
+ */
+ public void setDescriptionModel(URLEntryModel description) {
+ assertIsWriteable();
+ this.description = description;
+ }
+
+ /**
+ * Marks the model object as read-only.
+ *
+ * @since 2.0
+ */
+ public void markReadOnly() {
+ super.markReadOnly();
+ markReferenceReadOnly(getDescriptionModel());
+ }
+
+ /**
+ * Resolve the model object.
+ * Any URL strings in the model are resolved relative to the
+ * base URL argument. Any translatable strings in the model that are
+ * specified as translation keys are localized using the supplied
+ * resource bundle.
+ *
+ * @param base URL
+ * @param bundleURL resource bundle URL
+ * @exception MalformedURLException
+ * @since 2.0
+ */
+ public void resolve(URL base,URL bundleURL)
+ throws MalformedURLException {
+ // resolve local elements
+ localizedLabel = resolveNLString(bundleURL, label);
+
+ // delegate to references
+ resolveReference(getDescriptionModel(),base, bundleURL);
+ }
+
+ /**
+ * Compare two category models for equality.
+ *
+ * @see Object#equals(Object)
+ * @since 2.0
+ */
+ public boolean equals(Object obj) {
+ boolean result = false;
+ if (obj instanceof CategoryModel) {
+ CategoryModel otherCategory = (CategoryModel) obj;
+ result = getName().equalsIgnoreCase(otherCategory.getName());
+ }
+ return result;
+ }
+
+ /**
+ * Compute hash code for category model.
+ *
+ * @see Object#hashCode()
+ * @since 2.0
+ */
+ public int hashCode() {
+ return getName().hashCode();
+ }
+
+ /**
+ * Returns a comparator for category models.
+ *
+ * @return comparator
+ * @since 2.0
+ */
+ public static Comparator getComparator() {
+ if (comp == null) {
+ comp = new Comparator() {
+ /*
+ * @see Comparator#compare(Object,Object)
+ * Returns 0 if versions are equal.
+ * Returns -1 if object1 is after than object2.
+ * Returns +1 if object1 is before than object2.
+ */
+ public int compare(Object o1, Object o2) {
+
+ CategoryModel cat1 = (CategoryModel) o1;
+ CategoryModel cat2 = (CategoryModel) o2;
+
+ if (cat1.equals(cat2))
+ return 0;
+ return cat1.getName().compareTo(cat2.getName());
+ }
+ };
+ }
+ return comp;
+ }
+
+ /**
+ * @see org.eclipse.update.core.model.ModelObject#getPropertyName()
+ */
+ protected String getPropertyName() {
+ return Site.SITE_FILE;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/ContentEntryModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/ContentEntryModel.java
new file mode 100644
index 0000000..cf71f8d
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/ContentEntryModel.java
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+
+/**
+ * Content entry model object.
+ * This is the base class for plug-in and non-plug-in entry models.
+ * <p>
+ * This class must be subclassed 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>
+ * @see org.eclipse.update.core.model.PluginEntryModel
+ * @see org.eclipse.update.core.model.NonPluginEntryModel
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public abstract class ContentEntryModel extends ModelObject {
+
+ /**
+ * An indication the size could not be determined
+ *
+ * @since 2.0
+ */
+ public static final long UNKNOWN_SIZE = -1;
+
+ private long downloadSize = UNKNOWN_SIZE;
+ private long installSize = UNKNOWN_SIZE;
+ private String os;
+ private String ws;
+ private String nl;
+ private String arch;
+
+ /**
+ * Creates a uninitialized content entry model object.
+ *
+ * @since 2.0
+ */
+ protected ContentEntryModel() {
+ super();
+ }
+
+ /**
+ * Returns the download size of the entry, if it can be determined.
+ *
+ * @return download size of the entry in KiloBytes, or an indication
+ * the size could not be determined
+ * @since 2.0
+ */
+
+ public long getDownloadSize() {
+ return downloadSize;
+ }
+
+ /**
+ * Returns the install size of the entry, if it can be determined.
+ *
+ * @return install size of the entry in KiloBytes, or an indication
+ * the size could not be determined
+ * @since 2.0
+ */
+ public long getInstallSize() {
+ return installSize;
+ }
+
+ /**
+ * Returns optional operating system specification.
+ *
+ * @return the operating system specification or <code>null</code>.
+ * @since 2.0
+ */
+ public String getOS() {
+ return os;
+ }
+
+ /**
+ * Returns optional windowing system specification.
+ *
+ * @return the windowing system specification or <code>null</code>.
+ * @since 2.0
+ */
+
+ public String getWS() {
+ return ws;
+ }
+
+ /**
+ * Returns optional system architecture specification.
+ *
+ * @return the system architecture specification or <code>null</code>.
+ * @since 2.0
+ */
+ public String getOSArch() {
+ return arch;
+ }
+
+ /**
+ * Returns optional locale specification.
+ *
+ * @return the locale specification, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getNL() {
+ return nl;
+ }
+
+ /**
+ * Sets the download size of the entry.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param downloadSize download size of the entry in KiloBytes
+ * @since 2.0
+ */
+ public void setDownloadSize(long downloadSize) {
+ assertIsWriteable();
+ if (downloadSize < 0)
+ this.downloadSize = UNKNOWN_SIZE;
+ else
+ this.downloadSize = downloadSize;
+ }
+
+ /**
+ * Sets the install size of the entry.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param installSize install size of the entry in KiloBytes
+ * @since 2.0
+ */
+ public void setInstallSize(long installSize) {
+ assertIsWriteable();
+ if (installSize < 0)
+ this.installSize = UNKNOWN_SIZE;
+ else
+ this.installSize = installSize;
+ }
+
+ /**
+ * Sets the operating system specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param os comma-separated list of OS identifiers as defined by Eclipse.
+ * @since 2.0
+ */
+ public void setOS(String os) {
+ assertIsWriteable();
+ this.os = os;
+ }
+
+ /**
+ * Sets the windowing system specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param ws comma-separated list of WS identifiers as defined by Eclipse.
+ * @since 2.0
+ */
+ public void setWS(String ws) {
+ assertIsWriteable();
+ this.ws = ws;
+ }
+
+ /**
+ * Sets the system architecture specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param arch comma-separated list of arch identifiers as defined by Eclipse.
+ * @since 2.0
+ */
+ public void setArch(String arch) {
+ assertIsWriteable();
+ this.arch = arch;
+ }
+
+ /**
+ * Sets the locale specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param nl comma-separated list of locale identifiers.
+ * @since 2.0
+ */
+ public void setNL(String nl) {
+ assertIsWriteable();
+ this.nl = nl;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/DefaultFeatureParser.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/DefaultFeatureParser.java
new file mode 100644
index 0000000..89f9738
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/DefaultFeatureParser.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.update.internal.core.InternalFeatureParser;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Default feature parser.
+ * Parses the feature manifest file as defined by the platform. Defers
+ * to a model factory to create the actual concrete model objects. The
+ * update framework supplies two factory implementations:
+ * <ul>
+ * <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>
+ * <li>@see org.eclipse.update.core.model.FeatureModelFactory
+ * <li>@see org.eclipse.update.core.BaseFeatureFactory
+ * </ul>
+ *
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class DefaultFeatureParser extends DefaultHandler {
+
+ private InternalFeatureParser featureParser;
+
+
+ // Current State Information
+ //Stack stateStack = new Stack();
+
+ // Current object stack (used to hold the current object we are
+ // populating in this plugin descriptor
+ //Stack objectStack = new Stack();
+
+ /**
+ * Constructs a feature parser.
+ *
+ * @since 2.0
+ */
+ public DefaultFeatureParser() {
+ super();
+ featureParser = new InternalFeatureParser();
+ }
+
+ public void init(FeatureModelFactory factory) {
+ init(factory, null);
+ }
+
+ /**
+ * @param factory
+ * @param location
+ * @since 3.1
+ */
+ public void init(FeatureModelFactory factory, String location) {
+
+ this.featureParser.init(factory, location);
+ }
+
+ /**
+ * Parses the specified input steam and constructs a feature model.
+ * The input stream is not closed as part of this operation.
+ *
+ * @param in input stream
+ * @return feature model
+ * @exception SAXException
+ * @exception IOException
+ * @since 2.0
+ */
+ public FeatureModel parse(InputStream in) throws SAXException, IOException {
+ return featureParser.parse(in);
+ }
+
+ /**
+ * Returns all status objects accumulated by the parser.
+ *
+ * @return multi-status containing accumulated status, or <code>null</code>.
+ * @since 2.0
+ */
+ public MultiStatus getStatus() {
+ return featureParser.getStatus();
+ }
+
+ /**
+ * Handle start of element tags
+ * @see DefaultHandler#startElement(String, String, String, Attributes)
+ * @since 2.0
+ */
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ featureParser.startElement(uri, localName, qName, attributes);
+
+
+ }
+
+ /**
+ * Handle end of element tags
+ * @see DefaultHandler#endElement(String, String, String)
+ * @since 2.0
+ */
+ public void endElement(String uri, String localName, String qName) {
+ featureParser.endElement(uri, localName, qName);
+ }
+
+
+ /**
+ * Handle character text
+ * @see DefaultHandler#characters(char[], int, int)
+ * @since 2.0
+ */
+ public void characters(char[] ch, int start, int length) {
+ featureParser.characters(ch, start, length);
+ }
+
+ /**
+ * Handle errors
+ * @see DefaultHandler#error(SAXParseException)
+ * @since 2.0
+ */
+ public void error(SAXParseException ex) {
+ featureParser.error(ex);
+ }
+
+ /**
+ * Handle fatal errors
+ * @see DefaultHandler#fatalError(SAXParseException)
+ * @exception SAXException
+ * @since 2.0
+ */
+ public void fatalError(SAXParseException ex) throws SAXException {
+ featureParser.fatalError(ex);
+ }
+
+ /**
+ * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
+ */
+ public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
+ featureParser.ignorableWhitespace(arg0, arg1, arg2);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/DefaultSiteParser.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/DefaultSiteParser.java
new file mode 100644
index 0000000..e60d979
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/DefaultSiteParser.java
@@ -0,0 +1,890 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Stack;
+import java.util.StringTokenizer;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.IURLEntry;
+import org.eclipse.update.core.SiteFeatureReferenceModel;
+import org.eclipse.update.core.URLEntry;
+import org.eclipse.update.internal.core.ExtendedSite;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Default site parser.
+ * Parses the site manifest file as defined by the platform. Defers
+ * to a model factory to create the actual concrete model objects. The
+ * update framework supplies two factory implementations:
+ * <ul>
+ * <li>@see org.eclipse.update.core.model.SiteModelFactory
+ * <li>@see org.eclipse.update.core.BaseSiteFactory
+ * </ul>
+ *
+ * <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>
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class DefaultSiteParser extends DefaultHandler {
+
+ private final static SAXParserFactory parserFactory =
+ SAXParserFactory.newInstance();
+
+ private SAXParser parser;
+ private SiteModelFactory factory;
+
+ private MultiStatus status;
+
+ private boolean DESCRIPTION_SITE_ALREADY_SEEN = false;
+
+ private static final int STATE_IGNORED_ELEMENT = -1;
+ private static final int STATE_INITIAL = 0;
+ private static final int STATE_SITE = 1;
+ private static final int STATE_FEATURE = 2;
+ private static final int STATE_ARCHIVE = 3;
+ private static final int STATE_CATEGORY = 4;
+ private static final int STATE_CATEGORY_DEF = 5;
+ private static final int STATE_DESCRIPTION_SITE = 6;
+ private static final int STATE_DESCRIPTION_CATEGORY_DEF = 7;
+ private static final String PLUGIN_ID = UpdateCore.getPlugin().getBundle().getSymbolicName();
+
+ private static final String SITE = "site"; //$NON-NLS-1$
+ private static final String FEATURE = "feature"; //$NON-NLS-1$
+ private static final String ARCHIVE = "archive"; //$NON-NLS-1$
+ private static final String CATEGORY_DEF = "category-def"; //$NON-NLS-1$
+ private static final String CATEGORY = "category"; //$NON-NLS-1$
+ private static final String DESCRIPTION = "description"; //$NON-NLS-1$
+ private static final String MIRROR = "mirror"; //$NON-NLS-1$
+ //private static final String ASSOCIATE_SITES = "associateSites"; //$NON-NLS-1$
+ private static final String ASSOCIATE_SITE = "associateSite"; //$NON-NLS-1$
+
+ private static final String DEFAULT_INFO_URL = "index.html"; //$NON-NLS-1$
+ private static final String FEATURES = "features/"; //$NON-NLS-1$
+
+ // Current State Information
+ Stack stateStack = new Stack();
+
+ // Current object stack (used to hold the current object we are
+ // populating in this plugin descriptor
+ Stack objectStack = new Stack();
+
+ private int currentState;
+
+ /**
+ * Constructs a site parser.
+ */
+ public DefaultSiteParser() {
+ super();
+ try {
+ parserFactory.setNamespaceAware(true);
+ this.parser = parserFactory.newSAXParser();
+ } catch (ParserConfigurationException e) {
+ UpdateCore.log(e);
+ } catch (SAXException e) {
+ UpdateCore.log(e);
+ }
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("Created"); //$NON-NLS-1$
+ }
+
+ public void init(SiteModelFactory factory) {
+ // PERF: separate instance creation from parsing
+ this.factory = factory;
+ stateStack = new Stack();
+ objectStack = new Stack();
+ status = null;
+ DESCRIPTION_SITE_ALREADY_SEEN = false;
+ }
+
+ /**
+ * Parses the specified input steam and constructs a site model.
+ * The input stream is not closed as part of this operation.
+ *
+ * @param in input stream
+ * @return site model
+ * @exception SAXException
+ * @exception IOException
+ * @since 2.0
+ */
+ public SiteModel parse(InputStream in) throws SAXException, IOException {
+ stateStack.push(new Integer(STATE_INITIAL));
+ currentState = ((Integer) stateStack.peek()).intValue();
+ parser.parse(new InputSource(in), this);
+ if (objectStack.isEmpty())
+ throw new SAXException(Messages.DefaultSiteParser_NoSiteTag);
+ else {
+ if (objectStack.peek() instanceof SiteModel) {
+ return (SiteModel) objectStack.pop();
+ } else {
+ String stack = ""; //$NON-NLS-1$
+ Iterator iter = objectStack.iterator();
+ while (iter.hasNext()) {
+ stack = stack + iter.next().toString() + "\r\n"; //$NON-NLS-1$
+ }
+ throw new SAXException(NLS.bind(Messages.DefaultSiteParser_WrongParsingStack, (new String[] { stack })));
+ }
+ }
+ }
+
+ /**
+ * Returns all status objects accumulated by the parser.
+ *
+ * @return multi-status containing accumulated status, or <code>null</code>.
+ * @since 2.0
+ */
+ public MultiStatus getStatus() {
+ return status;
+ }
+
+ /**
+ * Handle start of element tags
+ * @see DefaultHandler#startElement(String, String, String, Attributes)
+ * @since 2.0
+ */
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
+ debug("State: " + currentState); //$NON-NLS-1$
+ debug("Start Element: uri:" + uri + " local Name:" + localName + " qName:" + qName);//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ switch (currentState) {
+ case STATE_IGNORED_ELEMENT :
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] { localName, getState(currentState) })));
+ break;
+ case STATE_INITIAL :
+ handleInitialState(localName, attributes);
+ break;
+
+ case STATE_SITE :
+ handleSiteState(localName, attributes);
+ break;
+
+ case STATE_FEATURE :
+ handleFeatureState(localName, attributes);
+ break;
+
+ case STATE_ARCHIVE :
+ handleSiteState(localName, attributes);
+ break;
+
+ case STATE_CATEGORY :
+ handleCategoryState(localName, attributes);
+ break;
+
+ case STATE_CATEGORY_DEF :
+ handleCategoryDefState(localName, attributes);
+ break;
+
+ case STATE_DESCRIPTION_SITE :
+ handleSiteState(localName, attributes);
+ break;
+
+ case STATE_DESCRIPTION_CATEGORY_DEF :
+ handleSiteState(localName, attributes);
+ break;
+
+ default :
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownStartState, (new String[] { getState(currentState) })));
+ break;
+ }
+ int newState = ((Integer) stateStack.peek()).intValue();
+ if (newState != STATE_IGNORED_ELEMENT)
+ currentState = newState;
+
+ }
+
+ /**
+ * Handle end of element tags
+ * @see DefaultHandler#endElement(String, String, String)
+ * @since 2.0
+ */
+ public void endElement(String uri, String localName, String qName) {
+
+ String text = null;
+ URLEntryModel info = null;
+
+ int state = ((Integer) stateStack.peek()).intValue();
+ switch (state) {
+ case STATE_IGNORED_ELEMENT :
+ case STATE_ARCHIVE :
+ case STATE_CATEGORY :
+ stateStack.pop();
+ break;
+
+ case STATE_INITIAL :
+ internalError(Messages.DefaultSiteParser_ParsingStackBackToInitialState);
+ break;
+
+ case STATE_SITE :
+ stateStack.pop();
+ if (objectStack.peek() instanceof String) {
+ text = (String) objectStack.pop();
+ SiteModel site = (SiteModel) objectStack.peek();
+ site.getDescriptionModel().setAnnotation(text);
+ }
+ //do not pop the object
+ break;
+
+ case STATE_FEATURE :
+ stateStack.pop();
+ objectStack.pop();
+ break;
+
+ case STATE_CATEGORY_DEF :
+ stateStack.pop();
+ if (objectStack.peek() instanceof String) {
+ text = (String) objectStack.pop();
+ CategoryModel category = (CategoryModel) objectStack.peek();
+ category.getDescriptionModel().setAnnotation(text);
+ }
+ objectStack.pop();
+ break;
+
+ case STATE_DESCRIPTION_SITE :
+ stateStack.pop();
+ text = ""; //$NON-NLS-1$
+ while (objectStack.peek() instanceof String) {
+ // add text, preserving at most one space between text fragments
+ String newText = (String) objectStack.pop();
+ if (trailingSpace(newText) && !leadingSpace(text)) {
+ text = " " + text; //$NON-NLS-1$
+ }
+ text = newText.trim() + text;
+ if (leadingSpace(newText) && !leadingSpace(text)) {
+ text = " " + text; //$NON-NLS-1$
+ }
+ }
+ text = text.trim();
+
+ info = (URLEntryModel) objectStack.pop();
+ if (text != null)
+ info.setAnnotation(text);
+
+ SiteModel siteModel = (SiteModel) objectStack.peek();
+ // override description.
+ // do not raise error as previous description may be default one
+ // when parsing site tag
+ if (DESCRIPTION_SITE_ALREADY_SEEN)
+ debug(NLS.bind(Messages.DefaultSiteParser_ElementAlreadySet, (new String[] { getState(state) })));
+ siteModel.setDescriptionModel(info);
+ DESCRIPTION_SITE_ALREADY_SEEN = true;
+ break;
+
+ case STATE_DESCRIPTION_CATEGORY_DEF :
+ stateStack.pop();
+ text = ""; //$NON-NLS-1$
+ while (objectStack.peek() instanceof String) {
+ // add text, preserving at most one space between text fragments
+ String newText = (String) objectStack.pop();
+ if (trailingSpace(newText) && !leadingSpace(text)) {
+ text = " " + text; //$NON-NLS-1$
+ }
+ text = newText.trim() + text;
+ if (leadingSpace(newText) && !leadingSpace(text)) {
+ text = " " + text; //$NON-NLS-1$
+ }
+ }
+ text = text.trim();
+
+ info = (URLEntryModel) objectStack.pop();
+ if (text != null)
+ info.setAnnotation(text);
+
+ CategoryModel category = (CategoryModel) objectStack.peek();
+ if (category.getDescriptionModel() != null)
+ internalError(NLS.bind(Messages.DefaultSiteParser_ElementAlreadySet, (new String[] { getState(state), category.getLabel() })));
+ else
+ category.setDescriptionModel(info);
+ break;
+
+ default :
+ internalError(NLS.bind(Messages.DefaultSiteParser_UnknownEndState, (new String[] { getState(state) })));
+ break;
+ }
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("End Element:" + uri + ":" + localName + ":" + qName);//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ /**
+ * Handle character text
+ * @see DefaultHandler#characters(char[], int, int)
+ * @since 2.0
+ */
+ public void characters(char[] ch, int start, int length) {
+ String text = new String(ch, start, length);
+ //only push if description
+ int state = ((Integer) stateStack.peek()).intValue();
+ if (state == STATE_DESCRIPTION_SITE || state == STATE_DESCRIPTION_CATEGORY_DEF)
+ objectStack.push(text);
+
+ }
+
+ /**
+ * Handle errors
+ * @see DefaultHandler#error(SAXParseException)
+ * @since 2.0
+ */
+ public void error(SAXParseException ex) {
+ logStatus(ex);
+ }
+
+ /**
+ * Handle fatal errors
+ * @see DefaultHandler#fatalError(SAXParseException)
+ * @exception SAXException
+ * @since 2.0
+ */
+ public void fatalError(SAXParseException ex) throws SAXException {
+ logStatus(ex);
+ throw ex;
+ }
+
+ private void handleInitialState(String elementName, Attributes attributes) throws SAXException {
+ if (elementName.equals(SITE)) {
+ stateStack.push(new Integer(STATE_SITE));
+ processSite(attributes);
+ } else {
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] { elementName, getState(currentState) })));
+ // what we received was not a site.xml, no need to continue
+ throw new SAXException(Messages.DefaultSiteParser_InvalidXMLStream);
+ }
+
+ }
+
+ private void handleSiteState(String elementName, Attributes attributes) {
+ if (elementName.equals(DESCRIPTION)) {
+ stateStack.push(new Integer(STATE_DESCRIPTION_SITE));
+ processInfo(attributes);
+ } else if (elementName.equals(FEATURE)) {
+ stateStack.push(new Integer(STATE_FEATURE));
+ processFeature(attributes);
+ } else if (elementName.equals(ARCHIVE)) {
+ stateStack.push(new Integer(STATE_ARCHIVE));
+ processArchive(attributes);
+ } else if (elementName.equals(CATEGORY_DEF)) {
+ stateStack.push(new Integer(STATE_CATEGORY_DEF));
+ processCategoryDef(attributes);
+ } else
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] { elementName, getState(currentState) })));
+ }
+
+ private void handleFeatureState(String elementName, Attributes attributes) {
+ if (elementName.equals(DESCRIPTION)) {
+ stateStack.push(new Integer(STATE_DESCRIPTION_SITE));
+ processInfo(attributes);
+ } else if (elementName.equals(FEATURE)) {
+ stateStack.push(new Integer(STATE_FEATURE));
+ processFeature(attributes);
+ } else if (elementName.equals(ARCHIVE)) {
+ stateStack.push(new Integer(STATE_ARCHIVE));
+ processArchive(attributes);
+ } else if (elementName.equals(CATEGORY_DEF)) {
+ stateStack.push(new Integer(STATE_CATEGORY_DEF));
+ processCategoryDef(attributes);
+ } else if (elementName.equals(CATEGORY)) {
+ stateStack.push(new Integer(STATE_CATEGORY));
+ processCategory(attributes);
+ } else
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] { elementName, getState(currentState) })));
+ }
+
+ private void handleCategoryDefState(String elementName, Attributes attributes) {
+ if (elementName.equals(FEATURE)) {
+ stateStack.push(new Integer(STATE_FEATURE));
+ processFeature(attributes);
+ } else if (elementName.equals(ARCHIVE)) {
+ stateStack.push(new Integer(STATE_ARCHIVE));
+ processArchive(attributes);
+ } else if (elementName.equals(CATEGORY_DEF)) {
+ stateStack.push(new Integer(STATE_CATEGORY_DEF));
+ processCategoryDef(attributes);
+ } else if (elementName.equals(DESCRIPTION)) {
+ stateStack.push(new Integer(STATE_DESCRIPTION_CATEGORY_DEF));
+ processInfo(attributes);
+ } else
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] { elementName, getState(currentState) })));
+ }
+
+ private void handleCategoryState(String elementName, Attributes attributes) {
+ if (elementName.equals(DESCRIPTION)) {
+ stateStack.push(new Integer(STATE_DESCRIPTION_SITE));
+ processInfo(attributes);
+ } else if (elementName.equals(FEATURE)) {
+ stateStack.push(new Integer(STATE_FEATURE));
+ processFeature(attributes);
+ } else if (elementName.equals(ARCHIVE)) {
+ stateStack.push(new Integer(STATE_ARCHIVE));
+ processArchive(attributes);
+ } else if (elementName.equals(CATEGORY_DEF)) {
+ stateStack.push(new Integer(STATE_CATEGORY_DEF));
+ processCategoryDef(attributes);
+ } else if (elementName.equals(CATEGORY)) {
+ stateStack.push(new Integer(STATE_CATEGORY));
+ processCategory(attributes);
+ } else
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] { elementName, getState(currentState) })));
+ }
+
+ /*
+ * process site info
+ */
+ private void processSite(Attributes attributes) throws SAXException {
+ // create site map
+ SiteModel site = factory.createSiteMapModel();
+
+ // if URL is specified, it replaces the URL of the site
+ // used to calculate the location of features and archives
+ String siteURL = attributes.getValue("url"); //$NON-NLS-1$
+ if (siteURL != null && !("".equals(siteURL.trim()))) { //$NON-NLS-1$
+ if (!siteURL.endsWith("/") && !siteURL.endsWith(File.separator)) { //$NON-NLS-1$
+ siteURL += "/"; //$NON-NLS-1$
+ }
+ site.setLocationURLString(siteURL);
+ }
+
+ // provide default description URL
+ // If <description> is specified, for the site, it takes precedence
+ URLEntryModel description = factory.createURLEntryModel();
+ description.setURLString(DEFAULT_INFO_URL);
+ site.setDescriptionModel(description);
+
+ // verify we can parse the site ...if the site has
+ // a different type throw an exception to force reparsing
+ // with the matching parser
+ String type = attributes.getValue("type"); //$NON-NLS-1$
+ if (!factory.canParseSiteType(type)) {
+ throw new SAXException(new InvalidSiteTypeException(type));
+ }
+ site.setType(type);
+
+ // get mirrors, if any
+ String mirrorsURL = attributes.getValue("mirrorsURL"); //$NON-NLS-1$
+ if (mirrorsURL != null && mirrorsURL.trim().length() > 0) {
+ URLEntryModel[] mirrors = getMirrors(mirrorsURL, factory);
+ if (mirrors != null)
+ site.setMirrorSiteEntryModels(mirrors);
+ else
+ site.setMirrorsURLString(mirrorsURL);
+ }
+
+ String pack200 = attributes.getValue("pack200"); //$NON-NLS-1$
+ if(site instanceof ExtendedSite && pack200 != null && new Boolean(pack200).booleanValue()){
+ ((ExtendedSite) site).setSupportsPack200(true);
+ }
+
+ if ( (site instanceof ExtendedSite) && (attributes.getValue("digestURL") != null)) { //$NON-NLS-1$
+ ExtendedSite extendedSite = (ExtendedSite) site;
+ extendedSite.setDigestExist(true);
+ extendedSite.setDigestURL(attributes.getValue("digestURL")); //$NON-NLS-1$
+
+ if ( (attributes.getValue("availableLocales") != null) && (!attributes.getValue("availableLocales").trim().equals(""))) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+ StringTokenizer locals = new StringTokenizer(attributes.getValue("availableLocales"), ","); //$NON-NLS-1$//$NON-NLS-2$
+ String[] availableLocals = new String[locals.countTokens()];
+ int i = 0;
+ while(locals.hasMoreTokens()) {
+ availableLocals[i++] = locals.nextToken();
+ }
+ extendedSite.setAvailableLocals(availableLocals);
+ }
+ }
+
+ if ( (site instanceof ExtendedSite) && (attributes.getValue("associateSitesURL") != null)) { //$NON-NLS-1$
+ IURLEntry[] associateSites = getAssociateSites(attributes.getValue("associateSitesURL"), factory); //$NON-NLS-1$
+ if (associateSites != null)
+ ((ExtendedSite)site).setAssociateSites(associateSites);
+ else
+ site.setMirrorsURLString(mirrorsURL);
+ }
+
+ objectStack.push(site);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("End process Site tag: siteURL:" + siteURL + " type:" + type);//$NON-NLS-1$ //$NON-NLS-2$
+
+ }
+
+ /*
+ * process feature info
+ */
+ private void processFeature(Attributes attributes) {
+ SiteFeatureReferenceModel feature = factory.createFeatureReferenceModel();
+
+ // feature location on the site
+ String urlInfo = attributes.getValue("url"); //$NON-NLS-1$
+ // identifier and version
+ String id = attributes.getValue("id"); //$NON-NLS-1$
+ String ver = attributes.getValue("version"); //$NON-NLS-1$
+
+ boolean noURL = (urlInfo == null || urlInfo.trim().equals("")); //$NON-NLS-1$
+ boolean noId = (id == null || id.trim().equals("")); //$NON-NLS-1$
+ boolean noVersion = (ver == null || ver.trim().equals("")); //$NON-NLS-1$
+
+ // We need to have id and version, or the url, or both.
+ if (noURL) {
+ if (noId || noVersion)
+ internalError(NLS.bind(Messages.DefaultSiteParser_Missing, (new String[] { "url", getState(currentState) }))); //$NON-NLS-1$
+ else // default url
+ urlInfo = FEATURES + id + '_' + ver; //
+ }
+
+ feature.setURLString(urlInfo);
+
+ String type = attributes.getValue("type"); //$NON-NLS-1$
+ feature.setType(type);
+
+ // if one is null, and not the other
+ if (noId ^ noVersion) {
+ String[] values = new String[] { id, ver, getState(currentState)};
+ UpdateCore.warn(NLS.bind(Messages.DefaultFeatureParser_IdOrVersionInvalid, values));
+ } else {
+ feature.setFeatureIdentifier(id);
+ feature.setFeatureVersion(ver);
+ }
+
+ // get label if it exists
+ String label = attributes.getValue("label"); //$NON-NLS-1$
+ if (label != null) {
+ if ("".equals(label.trim())) //$NON-NLS-1$
+ label = null;
+ }
+ feature.setLabel(label);
+
+ // OS
+ String os = attributes.getValue("os"); //$NON-NLS-1$
+ feature.setOS(os);
+
+ // WS
+ String ws = attributes.getValue("ws"); //$NON-NLS-1$
+ feature.setWS(ws);
+
+ // NL
+ String nl = attributes.getValue("nl"); //$NON-NLS-1$
+ feature.setNL(nl);
+
+ // arch
+ String arch = attributes.getValue("arch"); //$NON-NLS-1$
+ feature.setArch(arch);
+
+ //patch
+ String patch = attributes.getValue("patch"); //$NON-NLS-1$
+ feature.setPatch(patch);
+
+ SiteModel site = (SiteModel) objectStack.peek();
+ site.addFeatureReferenceModel(feature);
+ feature.setSiteModel(site);
+
+ objectStack.push(feature);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("End Processing DefaultFeature Tag: url:" + urlInfo + " type:" + type); //$NON-NLS-1$ //$NON-NLS-2$
+
+ }
+
+ /*
+ * process archive info
+ */
+ private void processArchive(Attributes attributes) {
+ ArchiveReferenceModel archive = factory.createArchiveReferenceModel();
+ String id = attributes.getValue("path"); //$NON-NLS-1$
+ if (id == null || id.trim().equals("")) { //$NON-NLS-1$
+ internalError(NLS.bind(Messages.DefaultSiteParser_Missing, (new String[] { "path", getState(currentState) }))); //$NON-NLS-1$
+ }
+
+ archive.setPath(id);
+
+ String url = attributes.getValue("url"); //$NON-NLS-1$
+ if (url == null || url.trim().equals("")) { //$NON-NLS-1$
+ internalError(NLS.bind(Messages.DefaultSiteParser_Missing, (new String[] { "archive", getState(currentState) }))); //$NON-NLS-1$
+ } else {
+ archive.setURLString(url);
+
+ SiteModel site = (SiteModel) objectStack.peek();
+ site.addArchiveReferenceModel(archive);
+ }
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("End processing Archive: path:" + id + " url:" + url);//$NON-NLS-1$ //$NON-NLS-2$
+
+ }
+
+ /*
+ * process the Category info
+ */
+ private void processCategory(Attributes attributes) {
+ String category = attributes.getValue("name"); //$NON-NLS-1$
+ SiteFeatureReferenceModel feature = (SiteFeatureReferenceModel) objectStack.peek();
+ feature.addCategoryName(category);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("End processing Category: name:" + category); //$NON-NLS-1$
+ }
+
+ /*
+ * process category def info
+ */
+ private void processCategoryDef(Attributes attributes) {
+ CategoryModel category = factory.createSiteCategoryModel();
+ String name = attributes.getValue("name"); //$NON-NLS-1$
+ String label = attributes.getValue("label"); //$NON-NLS-1$
+ category.setName(name);
+ category.setLabel(label);
+
+ SiteModel site = (SiteModel) objectStack.peek();
+ site.addCategoryModel(category);
+ objectStack.push(category);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("End processing CategoryDef: name:" + name + " label:" + label); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /*
+ * process URL info with element text
+ */
+ private void processInfo(Attributes attributes) {
+ URLEntryModel inf = factory.createURLEntryModel();
+ String infoURL = attributes.getValue("url"); //$NON-NLS-1$
+ inf.setURLString(infoURL);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("Processed Info: url:" + infoURL); //$NON-NLS-1$
+
+ objectStack.push(inf);
+ }
+
+ /*
+ *
+ */
+ private static void debug(String s) {
+ UpdateCore.debug("DefaultSiteParser" + s); //$NON-NLS-1$
+ }
+
+ /*
+ *
+ */
+ private void logStatus(SAXParseException ex) {
+ String name = ex.getSystemId();
+ if (name == null)
+ name = ""; //$NON-NLS-1$
+ else
+ name = name.substring(1 + name.lastIndexOf("/")); //$NON-NLS-1$
+
+ String msg;
+ if (name.equals("")) //$NON-NLS-1$
+ msg = NLS.bind(Messages.DefaultSiteParser_ErrorParsing, (new String[] { ex.getMessage() }));
+ else {
+ String[] values = new String[] { name, Integer.toString(ex.getLineNumber()), Integer.toString(ex.getColumnNumber()), ex.getMessage()};
+ msg = NLS.bind(Messages.DefaultSiteParser_ErrorlineColumnMessage, values);
+ }
+ error(new Status(IStatus.ERROR, PLUGIN_ID, Platform.PARSE_PROBLEM, msg, ex));
+ }
+
+ /*
+ * Handles an error state specified by the status. The collection of all logged status
+ * objects can be accessed using <code>getStatus()</code>.
+ *
+ * @param error a status detailing the error condition
+ */
+ private void error(IStatus error) {
+
+ if (status == null) {
+ status = new MultiStatus(PLUGIN_ID, Platform.PARSE_PROBLEM, Messages.DefaultSiteParser_ErrorParsingSite, null);
+ }
+
+ status.add(error);
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ UpdateCore.log(error);
+ }
+
+ /*
+ *
+ */
+ private void internalErrorUnknownTag(String msg) {
+ stateStack.push(new Integer(STATE_IGNORED_ELEMENT));
+ internalError(msg);
+ }
+
+ /*
+ *
+ */
+ private void internalError(String message) {
+ error(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.OK, message, null));
+ }
+
+ /*
+ * return the state as String
+ */
+ private String getState(int state) {
+
+ switch (state) {
+ case STATE_IGNORED_ELEMENT :
+ return "Ignored"; //$NON-NLS-1$
+
+ case STATE_INITIAL :
+ return "Initial"; //$NON-NLS-1$
+
+ case STATE_SITE :
+ return "Site"; //$NON-NLS-1$
+
+ case STATE_FEATURE :
+ return "Feature"; //$NON-NLS-1$
+
+ case STATE_ARCHIVE :
+ return "Archive"; //$NON-NLS-1$
+
+ case STATE_CATEGORY :
+ return "Category"; //$NON-NLS-1$
+
+ case STATE_CATEGORY_DEF :
+ return "Category Def"; //$NON-NLS-1$
+
+ case STATE_DESCRIPTION_CATEGORY_DEF :
+ return "Description / Category Def"; //$NON-NLS-1$
+
+ case STATE_DESCRIPTION_SITE :
+ return "Description / Site"; //$NON-NLS-1$
+
+ default :
+ return Messages.DefaultSiteParser_UnknownState;
+ }
+ }
+ private boolean leadingSpace(String str) {
+ if (str.length() <= 0) {
+ return false;
+ }
+ return Character.isWhitespace(str.charAt(0));
+ }
+ private boolean trailingSpace(String str) {
+ if (str.length() <= 0) {
+ return false;
+ }
+ return Character.isWhitespace(str.charAt(str.length() - 1));
+ }
+
+ static URLEntryModel[] getMirrors(String mirrorsURL, SiteModelFactory factory) {
+
+ try {
+ String countryCode = Locale.getDefault().getCountry().toLowerCase();
+ int timeZone = (new GregorianCalendar()).get(Calendar.ZONE_OFFSET)/(60*60*1000);
+
+ if (mirrorsURL.indexOf("?") != -1) { //$NON-NLS-1$
+ mirrorsURL = mirrorsURL + "&"; //$NON-NLS-1$
+ } else {
+ mirrorsURL = mirrorsURL + "?"; //$NON-NLS-1$
+ }
+ mirrorsURL = mirrorsURL + "countryCode=" + countryCode + "&timeZone=" + timeZone + "&responseType=xml"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ DocumentBuilderFactory domFactory =
+ DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = domFactory.newDocumentBuilder();
+ Document document = builder.parse(mirrorsURL);
+ if (document == null)
+ return null;
+ NodeList mirrorNodes = document.getElementsByTagName(MIRROR);
+ URLEntryModel[] mirrors = new URLEntryModel[mirrorNodes.getLength()];
+ for (int i=0; i<mirrorNodes.getLength(); i++) {
+ Element mirrorNode = (Element)mirrorNodes.item(i);
+ mirrors[i] = factory.createURLEntryModel();
+ String infoURL = mirrorNode.getAttribute("url"); //$NON-NLS-1$
+ String label = mirrorNode.getAttribute("label"); //$NON-NLS-1$
+ mirrors[i].setURLString(infoURL);
+ mirrors[i].setAnnotation(label);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("Processed mirror: url:" + infoURL + " label:" + label); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return mirrors;
+ }
+ catch (Exception e) {
+ // log if absolute url
+ if (mirrorsURL != null &&
+ (mirrorsURL.startsWith("http://") //$NON-NLS-1$
+ || mirrorsURL.startsWith("https://") //$NON-NLS-1$
+ || mirrorsURL.startsWith("file://") //$NON-NLS-1$
+ || mirrorsURL.startsWith("ftp://") //$NON-NLS-1$
+ || mirrorsURL.startsWith("jar://"))) //$NON-NLS-1$
+ UpdateCore.log(Messages.DefaultSiteParser_mirrors, e);
+ return null;
+ }
+ }
+
+ private static IURLEntry[] getAssociateSites(String associateSitesURL, SiteModelFactory factory) {
+
+ try {
+ DocumentBuilderFactory domFactory =
+ DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = domFactory.newDocumentBuilder();
+ Document document = builder.parse(associateSitesURL);
+ if (document == null)
+ return null;
+ NodeList mirrorNodes = document.getElementsByTagName(ASSOCIATE_SITE);
+ URLEntry[] mirrors = new URLEntry[mirrorNodes.getLength()];
+ for (int i=0; i<mirrorNodes.getLength(); i++) {
+ Element mirrorNode = (Element)mirrorNodes.item(i);
+ mirrors[i] = new URLEntry();
+ String infoURL = mirrorNode.getAttribute("url"); //$NON-NLS-1$
+ String label = mirrorNode.getAttribute("label"); //$NON-NLS-1$
+ mirrors[i].setURLString(infoURL);
+ mirrors[i].setAnnotation(label);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("Processed mirror: url:" + infoURL + " label:" + label); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return mirrors;
+ }
+ catch (Exception e) {
+ // log if absolute url
+ if (associateSitesURL != null &&
+ (associateSitesURL.startsWith("http://") //$NON-NLS-1$
+ || associateSitesURL.startsWith("https://") //$NON-NLS-1$
+ || associateSitesURL.startsWith("file://") //$NON-NLS-1$
+ || associateSitesURL.startsWith("ftp://") //$NON-NLS-1$
+ || associateSitesURL.startsWith("jar://"))) //$NON-NLS-1$
+ UpdateCore.log(Messages.DefaultSiteParser_mirrors, e);
+ return null;
+ }
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/FeatureModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/FeatureModel.java
new file mode 100644
index 0000000..6535672
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/FeatureModel.java
@@ -0,0 +1,946 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 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
+ * James D Miles (IBM Corp.) - bug 191783, NullPointerException in FeatureDownloader
+ *******************************************************************************/
+
+package org.eclipse.update.core.model;
+
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.update.core.IIncludedFeatureReference;
+import org.eclipse.update.core.IncludedFeatureReference;
+import org.eclipse.update.core.VersionedIdentifier;
+import org.eclipse.update.internal.core.UpdateCore;
+
+/**
+ * Feature model object.
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead instantiate or subclass the provided
+ * concrete implementation of this model.
+ * </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>
+ * @see org.eclipse.update.core.Feature
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class FeatureModel extends ModelObject {
+
+ private String featureId;
+ private String featureVersion;
+ private String label;
+ private String localizedLabel;
+ private String provider;
+ private String localizedProvider;
+ private String imageURLString;
+ private URL imageURL;
+ private String os;
+ private String ws;
+ private String nl;
+ private String arch;
+ private boolean primary = false;
+ private boolean exclusive=false;
+ private String primaryPluginID;
+ private String application;
+ private String affinity;
+ private InstallHandlerEntryModel installHandler;
+ private URLEntryModel description;
+ private URLEntryModel copyright;
+ private URLEntryModel license;
+ private URLEntryModel updateSiteInfo;
+ private List /*of InfoModel*/ discoverySiteInfo;
+ private List /*of ImportModel*/ imports;
+ private List /*of PluginEntryModel*/ pluginEntries;
+ private List /*of IncludedFeatureReferenceModel */ featureIncludes;
+ private List /*of NonPluginEntryModel*/ nonPluginEntries;
+
+ // performance
+ private URL bundleURL;
+ private URL base;
+ private boolean resolved = false;
+
+ /**
+ * Creates an uninitialized feature object.
+ *
+ * @since 2.0
+ */
+ public FeatureModel() {
+ super();
+ }
+
+ /**
+ * Compares 2 feature models for equality
+ *
+ * @param obj feature model to compare with
+ * @return <code>true</code> if the two models are equal,
+ * <code>false</code> otherwise
+ * @since 2.0
+ */
+ public boolean equals(Object obj) {
+ if (!(obj instanceof FeatureModel))
+ return false;
+ FeatureModel model = (FeatureModel) obj;
+
+ return (featureId.toLowerCase().equals(model.getFeatureIdentifier()) && featureVersion.toLowerCase().equals(model.getFeatureVersion()));
+ }
+
+ /**
+ * Returns the feature identifier as a string
+ *
+ * @see org.eclipse.update.core.IFeature#getVersionedIdentifier()
+ * @return feature identifier
+ * @since 2.0
+ */
+ public String getFeatureIdentifier() {
+ //delayedResolve(); no delay
+ return featureId;
+ }
+
+ /**
+ * Returns the feature version as a string
+ *
+ * @see org.eclipse.update.core.IFeature#getVersionedIdentifier()
+ * @return feature version
+ * @since 2.0
+ */
+ public String getFeatureVersion() {
+ //delayedResolve(); no delay
+ return featureVersion;
+ }
+
+ /**
+ * Retrieve the displayable label for the feature. If the model
+ * object has been resolved, the label is localized.
+ *
+ * @return displayable label, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getLabel() {
+ delayedResolve();
+ if (localizedLabel != null)
+ return localizedLabel;
+ else
+ return label;
+ }
+
+ /**
+ * Retrieve the non-localized displayable label for the feature.
+ *
+ * @return non-localized displayable label, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getLabelNonLocalized() {
+ return label;
+ }
+
+ /**
+ * Retrieve the displayable label for the feature provider. If the model
+ * object has been resolved, the label is localized.
+ *
+ * @return displayable label, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getProvider() {
+ delayedResolve();
+ if (localizedProvider != null)
+ return localizedProvider;
+ else
+ return provider;
+ }
+
+ /**
+ * Retrieve the non-localized displayable label for the feature provider.
+ *
+ * @return non-localized displayable label, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getProviderNonLocalized() {
+ return provider;
+ }
+
+ /**
+ * Returns the unresolved URL string for the feature image.
+ *
+ * @return url string, or <code>null</code>
+ * @since 2.0
+ */
+ public String getImageURLString() {
+ delayedResolve();
+ return imageURLString;
+ }
+
+ /**
+ * Returns the resolved URL for the image.
+ *
+ * @return url, or <code>null</code>
+ * @since 2.0
+ */
+ public URL getImageURL() {
+ delayedResolve();
+ return imageURL;
+ }
+
+ /**
+ * Get optional operating system specification as a comma-separated string.
+ *
+ * @return the operating system specification string, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getOS() {
+ return os;
+ }
+
+ /**
+ * Get optional windowing system specification as a comma-separated string.
+ * @return the windowing system specification string, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getWS() {
+ return ws;
+ }
+
+ /**
+ * Get optional system architecture specification as a comma-separated string.
+ *
+ * @return the system architecture specification string, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getOSArch() {
+ return arch;
+ }
+
+ /**
+ * Get optional locale specification as a comma-separated string.
+ *
+ * @return the locale specification string, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getNL() {
+ return nl;
+ }
+
+ /**
+ * Indicates whether the feature can be used as a primary feature.
+ *
+ * @return <code>true</code> if this is a primary feature,
+ * otherwise <code>false</code>
+ * @since 2.0
+ */
+ public boolean isPrimary() {
+ return primary;
+ }
+
+ /**
+ * Indicates whether the feature must be processed alone
+ * during installation and configuration. Features that
+ * are not exclusive can be installed in a batch.
+ *
+ * @return <code>true</code> if feature requires
+ * exclusive processing, <code>false</code> otherwise.
+ * @since 2.1
+ */
+ public boolean isExclusive() {
+ return exclusive;
+ }
+
+ /**
+ * Returns an optional identifier for the feature application
+ *
+ * @return application identifier, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getApplication() {
+ return application;
+ }
+
+ /**
+ * Returns an optional identifier for the colocation affinity feature
+ *
+ * @return feature identifier, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getAffinityFeature() {
+ return affinity;
+ }
+
+ /**
+ * Returns and optional custom install handler entry.
+ *
+ * @return install handler entry, or <code>null</code> if
+ * none was specified
+ * @since 2.0
+ */
+ public InstallHandlerEntryModel getInstallHandlerModel() {
+ //delayedResolve(); no delay
+ return installHandler;
+ }
+
+ /**
+ * Returns the feature description.
+ *
+ * @return feature rescription, or <code>null</code>.
+ * @since 2.0
+ */
+ public URLEntryModel getDescriptionModel() {
+ //delayedResolve(); no delay
+ return description;
+ }
+
+ /**
+ * Returns the copyright information for the feature.
+ *
+ * @return copyright information, or <code>null</code>.
+ * @since 2.0
+ */
+ public URLEntryModel getCopyrightModel() {
+ //delayedResolve(); no delay
+ return copyright;
+ }
+
+ /**
+ * Returns the license information for the feature.
+ *
+ * @return feature license, or <code>null</code>.
+ * @since 2.0
+ */
+ public URLEntryModel getLicenseModel() {
+ //delayedResolve(); no delay;
+ return license;
+ }
+
+ /**
+ * Returns an information entry referencing the location of the
+ * feature update site.
+ *
+ * @return update site entry, or <code>null</code>.
+ * @since 2.0
+ */
+ public URLEntryModel getUpdateSiteEntryModel() {
+ //delayedResolve(); no delay;
+ return updateSiteInfo;
+ }
+
+ /**
+ * Return an array of information entries referencing locations of other
+ * update sites.
+ *
+ * @return an array of site entries, or an empty array.
+ * @since 2.0
+ * @since 2.0
+ */
+ public URLEntryModel[] getDiscoverySiteEntryModels() {
+ //delayedResolve(); no delay;
+ if (discoverySiteInfo == null || discoverySiteInfo.size() == 0)
+ return new URLEntryModel[0];
+
+ return (URLEntryModel[]) discoverySiteInfo.toArray(arrayTypeFor(discoverySiteInfo));
+ }
+
+ /**
+ * Return a list of plug-in dependencies for this feature.
+ *
+ * @return the list of required plug-in dependencies, or an empty array.
+ * @since 2.0
+ */
+ public ImportModel[] getImportModels() {
+ //delayedResolve(); no delay;
+ if (imports == null || imports.size() == 0)
+ return new ImportModel[0];
+
+ return (ImportModel[]) imports.toArray(arrayTypeFor(imports));
+ }
+
+ /**
+ * Returns an array of plug-in entries referenced by this feature
+ *
+ * @return an erray of plug-in entries, or an empty array.
+ * @since 2.0
+ */
+ public PluginEntryModel[] getPluginEntryModels() {
+ if (pluginEntries == null || pluginEntries.size() == 0)
+ return new PluginEntryModel[0];
+
+ return (PluginEntryModel[]) pluginEntries.toArray(arrayTypeFor(pluginEntries));
+ }
+
+ /**
+ * Returns an array of versioned identifier referenced by this feature
+ *
+ * @return an array of versioned identifier, or an empty array.
+ * @deprecated use getFeatureIncludeIdentifier instead.
+ * @since 2.0
+ */
+ public VersionedIdentifier[] getFeatureIncludeVersionedIdentifier() {
+ //delayedResolve(); no delay
+ if (featureIncludes == null)
+ return new VersionedIdentifier[0];
+
+ //
+ Iterator iter = featureIncludes.iterator();
+ VersionedIdentifier[] versionIncluded = new VersionedIdentifier[featureIncludes.size()];
+ int index = 0;
+ while (iter.hasNext()) {
+ IncludedFeatureReferenceModel model = (IncludedFeatureReferenceModel) iter.next();
+ versionIncluded[index] = model.getVersionedIdentifier();
+ index++;
+ }
+ return versionIncluded;
+ }
+
+ /**
+ * Returns an array of included feature reference model referenced by this feature.
+ *
+ * @return an array of included feature reference model, or an empty array.
+ * @since 2.0
+ */
+ public IIncludedFeatureReference[] getFeatureIncluded() {
+ //delayedResolve(); no delay
+ if (featureIncludes == null || featureIncludes.size() == 0)
+ return new IIncludedFeatureReference[0];
+ return (IIncludedFeatureReference[]) featureIncludes.toArray(arrayTypeFor(featureIncludes));
+ }
+
+ /**
+ * Returns an array of non-plug-in entries referenced by this feature
+ *
+ * @return an erray of non-plug-in entries, or an empty array.
+ * @since 2.0
+ */
+ public NonPluginEntryModel[] getNonPluginEntryModels() {
+ if (nonPluginEntries == null || nonPluginEntries.size() == 0)
+ return new NonPluginEntryModel[0];
+
+ return (NonPluginEntryModel[]) nonPluginEntries.toArray(arrayTypeFor(nonPluginEntries));
+ }
+
+ /**
+ * Sets the feature identifier.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param featureId feature identifier
+ * @since 2.0
+ */
+ public void setFeatureIdentifier(String featureId) {
+ assertIsWriteable();
+ this.featureId = featureId;
+ }
+
+ /**
+ * Sets the feature version.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param featureVersion feature version
+ * @since 2.0
+ */
+ public void setFeatureVersion(String featureVersion) {
+ assertIsWriteable();
+ this.featureVersion = featureVersion;
+ }
+
+ /**
+ * Sets the feature displayable label.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param label displayable label
+ * @since 2.0
+ */
+ public void setLabel(String label) {
+ assertIsWriteable();
+ this.label = label;
+ this.localizedLabel = null;
+ }
+
+ /**
+ * Sets the feature provider displayable label.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param provider provider displayable label
+ * @since 2.0
+ */
+ public void setProvider(String provider) {
+ assertIsWriteable();
+ this.provider = provider;
+ this.localizedProvider = null;
+ }
+
+ /**
+ * Sets the unresolved URL for the feature image.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param imageURLString unresolved URL string
+ * @since 2.0
+ */
+ public void setImageURLString(String imageURLString) {
+ assertIsWriteable();
+ this.imageURLString = imageURLString;
+ this.imageURL = null;
+ }
+
+ /**
+ * Sets the operating system specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param os operating system specification as a comma-separated list
+ * @since 2.0
+ */
+ public void setOS(String os) {
+ assertIsWriteable();
+ this.os = os;
+ }
+
+ /**
+ * Sets the windowing system specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param ws windowing system specification as a comma-separated list
+ * @since 2.0
+ */
+ public void setWS(String ws) {
+ assertIsWriteable();
+ this.ws = ws;
+ }
+
+ /**
+ * Sets the locale specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param nl locale specification as a comma-separated list
+ * @since 2.0
+ */
+ public void setNL(String nl) {
+ assertIsWriteable();
+ this.nl = nl;
+ }
+
+ /**
+ * Sets the system architecture specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param arch system architecture specification as a comma-separated list
+ * @since 2.0
+ */
+ public void setArch(String arch) {
+ assertIsWriteable();
+ this.arch = arch;
+ }
+
+ /**
+ * Indicates whether this feature can act as a primary feature.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param primary <code>true</code> if this feature can act as primary,
+ * <code>false</code> otherwise
+ *
+ * @since 2.0
+ */
+ public void setPrimary(boolean primary) {
+ assertIsWriteable();
+ this.primary = primary;
+ }
+
+ /**
+ * Indicates whether this feature can act as a primary feature.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param exclusive <code>true</code> if this feature must be
+ * processed independently from other features, <code>false</code>
+ * if feature can be processed in a batch with other features.
+ *
+ * @since 2.1
+ */
+ public void setExclusive(boolean exclusive) {
+ assertIsWriteable();
+ this.exclusive = exclusive;
+ }
+
+ /**
+ * Sets the feature application identifier.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param application feature application identifier
+ * @since 2.0
+ */
+ public void setApplication(String application) {
+ assertIsWriteable();
+ this.application = application;
+ }
+
+ /**
+ * Sets the identifier of the Feature this feature should be
+ * installed with.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param affinity the identifier of the Feature
+ * @since 2.0
+ */
+ public void setAffinityFeature(String affinity) {
+ assertIsWriteable();
+ this.affinity = affinity;
+ }
+
+ /**
+ * Sets the custom install handler for the feature.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param installHandler install handler entry
+ * @since 2.0
+ */
+ public void setInstallHandlerModel(InstallHandlerEntryModel installHandler) {
+ assertIsWriteable();
+ this.installHandler = installHandler;
+ }
+
+ /**
+ * Sets the feature description information.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param description feature description information
+ * @since 2.0
+ */
+ public void setDescriptionModel(URLEntryModel description) {
+ assertIsWriteable();
+ this.description = description;
+ }
+
+ /**
+ * Sets the feature copyright information.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param copyright feature copyright information
+ * @since 2.0
+ */
+ public void setCopyrightModel(URLEntryModel copyright) {
+ assertIsWriteable();
+ this.copyright = copyright;
+ }
+
+ /**
+ * Sets the feature license information.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param license feature license information
+ * @since 2.0
+ */
+ public void setLicenseModel(URLEntryModel license) {
+ assertIsWriteable();
+ this.license = license;
+ }
+
+ /**
+ * Sets the feature update site reference.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param updateSiteInfo feature update site reference
+ * @since 2.0
+ */
+ public void setUpdateSiteEntryModel(URLEntryModel updateSiteInfo) {
+ assertIsWriteable();
+ this.updateSiteInfo = updateSiteInfo;
+ }
+
+ /**
+ * Sets additional update site references.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param discoverySiteInfo additional update site references
+ * @since 2.0
+ */
+ public void setDiscoverySiteEntryModels(URLEntryModel[] discoverySiteInfo) {
+ assertIsWriteable();
+ if (discoverySiteInfo == null)
+ this.discoverySiteInfo = null;
+ else
+ this.discoverySiteInfo = new ArrayList(Arrays.asList(discoverySiteInfo));
+ }
+
+ /**
+ * Sets the feature plug-in dependency information.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param imports feature plug-in dependency information
+ * @since 2.0
+ */
+ public void setImportModels(ImportModel[] imports) {
+ assertIsWriteable();
+ if (imports == null)
+ this.imports = null;
+ else
+ this.imports = new ArrayList(Arrays.asList(imports));
+ }
+
+ /**
+ * Sets the feature plug-in references.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param pluginEntries feature plug-in references
+ * @since 2.0
+ */
+ public void setPluginEntryModels(PluginEntryModel[] pluginEntries) {
+ assertIsWriteable();
+ if (pluginEntries == null)
+ this.pluginEntries = null;
+ else
+ this.pluginEntries = new ArrayList(Arrays.asList(pluginEntries));
+ }
+
+ /**
+ * Sets the feature non-plug-in data references.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param nonPluginEntries feature non-plug-in data references
+ * @since 2.0
+ */
+ public void setNonPluginEntryModels(NonPluginEntryModel[] nonPluginEntries) {
+ assertIsWriteable();
+ if (nonPluginEntries == null)
+ this.nonPluginEntries = null;
+ else
+ this.nonPluginEntries = new ArrayList(Arrays.asList(nonPluginEntries));
+ }
+
+ /**
+ * Adds an additional update site reference.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param discoverySiteInfo update site reference
+ * @since 2.0
+ */
+ public void addDiscoverySiteEntryModel(URLEntryModel discoverySiteInfo) {
+ assertIsWriteable();
+ if (this.discoverySiteInfo == null)
+ this.discoverySiteInfo = new ArrayList();
+ if (!this.discoverySiteInfo.contains(discoverySiteInfo))
+ this.discoverySiteInfo.add(discoverySiteInfo);
+ }
+
+ /**
+ * Adds a plug-in dependency entry.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param importEntry plug-in dependency entry
+ * @since 2.0
+ */
+ public void addImportModel(ImportModel importEntry) {
+ assertIsWriteable();
+ if (this.imports == null)
+ this.imports = new ArrayList();
+ if (!this.imports.contains(importEntry))
+ this.imports.add(importEntry);
+ }
+
+ /**
+ * Adds a plug-in reference.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param pluginEntry plug-in reference
+ * @since 2.0
+ */
+ public void addPluginEntryModel(PluginEntryModel pluginEntry) {
+ assertIsWriteable();
+ if (this.pluginEntries == null)
+ this.pluginEntries = new ArrayList();
+ //PERF: no ListContains()
+ //if (!this.pluginEntries.contains(pluginEntry))
+ this.pluginEntries.add(pluginEntry);
+ }
+
+ /**
+ * Adds a feature identifier.
+ * Throws a runtime exception if this object is marked read-only.
+ * @param include the included feature
+ * @since 2.1
+ */
+ public void addIncludedFeatureReferenceModel(IncludedFeatureReferenceModel include) {
+ assertIsWriteable();
+ if (this.featureIncludes == null)
+ this.featureIncludes = new ArrayList();
+ //PERF: no ListContains()
+ //if (!this.featureIncludes.contains(include))
+ this.featureIncludes.add(new IncludedFeatureReference(include));
+ }
+
+ /**
+ * Adds a non-plug-in data reference.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param nonPluginEntry non-plug-in data reference
+ * @since 2.0
+ */
+ public void addNonPluginEntryModel(NonPluginEntryModel nonPluginEntry) {
+ assertIsWriteable();
+ if (this.nonPluginEntries == null)
+ this.nonPluginEntries = new ArrayList();
+ //PERF: no ListContains()
+ //if (!this.nonPluginEntries.contains(nonPluginEntry))
+ this.nonPluginEntries.add(nonPluginEntry);
+ }
+
+ /**
+ * Removes an update site reference.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param discoverySiteInfo update site reference
+ * @since 2.0
+ */
+ public void removeDiscoverySiteEntryModel(URLEntryModel discoverySiteInfo) {
+ assertIsWriteable();
+ if (this.discoverySiteInfo != null)
+ this.discoverySiteInfo.remove(discoverySiteInfo);
+ }
+
+ /**
+ * Removes a plug-in dependency entry.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param importEntry plug-in dependency entry
+ * @since 2.0
+ */
+ public void removeImportModel(ImportModel importEntry) {
+ assertIsWriteable();
+ if (this.imports != null)
+ this.imports.remove(importEntry);
+ }
+
+ /**
+ * Removes a plug-in reference.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param pluginEntry plug-in reference
+ * @since 2.0
+ */
+ public void removePluginEntryModel(PluginEntryModel pluginEntry) {
+ assertIsWriteable();
+ if (this.pluginEntries != null)
+ this.pluginEntries.remove(pluginEntry);
+ }
+
+ /**
+ * Removes a non-plug-in data reference.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param nonPluginEntry non-plug-in data reference
+ * @since 2.0
+ */
+ public void removeNonPluginEntryModel(NonPluginEntryModel nonPluginEntry) {
+ assertIsWriteable();
+ if (this.nonPluginEntries != null)
+ this.nonPluginEntries.remove(nonPluginEntry);
+ }
+
+ /**
+ * Marks the model object as read-only.
+ *
+ * @since 2.0
+ */
+ public void markReadOnly() {
+ super.markReadOnly();
+ markReferenceReadOnly(getDescriptionModel());
+ markReferenceReadOnly(getCopyrightModel());
+ markReferenceReadOnly(getLicenseModel());
+ markReferenceReadOnly(getUpdateSiteEntryModel());
+ markListReferenceReadOnly(getDiscoverySiteEntryModels());
+ markListReferenceReadOnly(getImportModels());
+ markListReferenceReadOnly(getPluginEntryModels());
+ markListReferenceReadOnly(getNonPluginEntryModels());
+ }
+
+ /**
+ * Resolve the model object.
+ * Any URL strings in the model are resolved relative to the
+ * base URL argument. Any translatable strings in the model that are
+ * specified as translation keys are localized using the supplied
+ * resource bundle.
+ *
+ * @param base URL
+ * @param bundleURL resource bundle url
+ * @exception MalformedURLException
+ * @since 2.0
+ */
+ public void resolve(URL base,URL bundleURL) throws MalformedURLException {
+ this.bundleURL = bundleURL;
+ this.base = base;
+
+ // plugin entry and nonpluginentry are optimized too
+ resolveListReference(getPluginEntryModels(), base, bundleURL);
+ resolveListReference(getNonPluginEntryModels(), base, bundleURL);
+
+ //URLSiteModel are optimized
+ resolveReference(getDescriptionModel(),base, bundleURL);
+ resolveReference(getCopyrightModel(),base, bundleURL);
+ resolveReference(getLicenseModel(),base, bundleURL);
+ resolveReference(getUpdateSiteEntryModel(),base, bundleURL);
+ resolveListReference(getDiscoverySiteEntryModels(),base, bundleURL);
+
+ // Import Models are optimized
+ resolveListReference(getImportModels(),base, bundleURL);
+ }
+
+ private void delayedResolve() {
+
+ // PERF: delay resolution
+ if (resolved)
+ return;
+
+ // resolve local elements
+ localizedLabel = resolveNLString(bundleURL, label);
+ localizedProvider = resolveNLString(bundleURL, provider);
+ try {
+ imageURL = resolveURL(base,bundleURL, imageURLString);
+ resolved = true;
+ } catch (MalformedURLException e){
+ UpdateCore.warn("",e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Method setPrimaryPlugin.
+ * @param plugin
+ */
+ public void setPrimaryPluginID(String plugin) {
+ if (primary && primaryPluginID == null) {
+ primaryPluginID = featureId;
+ }
+ primaryPluginID = plugin;
+ }
+ /**
+ * Returns the primaryPluginID.
+ * @return String
+ */
+ public String getPrimaryPluginID() {
+ return primaryPluginID;
+ }
+
+ /**
+ * Returns <code>true</code> if this feature is patching another feature,
+ * <code>false</code> otherwise
+ * @return boolean
+ */
+ public boolean isPatch() {
+ ImportModel[] imports = getImportModels();
+
+ for (int i = 0; i < imports.length; i++) {
+ if (imports[i].isPatch())
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/FeatureModelFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/FeatureModelFactory.java
new file mode 100644
index 0000000..4af40a5
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/FeatureModelFactory.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.internal.core.Messages;
+import org.xml.sax.SAXException;
+
+/**
+ * Default feature model factory.
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead subclass the provided base implementation
+ * of this factory.
+ * </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>
+ * @see org.eclipse.update.core.BaseFeatureFactory
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class FeatureModelFactory {
+
+
+ //private static DefaultFeatureParser parser = new DefaultFeatureParser();
+
+ /**
+ * Creates a default model factory.
+ *
+ * @since 2.0
+ */
+ public FeatureModelFactory() {
+ super();
+ }
+
+ /**
+ * Creates and populates a default feature from stream.
+ * The parser assumes the stream contains a default feature manifest
+ * (feature.xml) as documented by the platform.
+ *
+ * @param stream feature stream
+ * @return populated feature model
+ * @exception CoreException
+ * @exception SAXException
+ * @since 2.0
+ */
+ public FeatureModel parseFeature(InputStream stream)
+ throws CoreException, SAXException {
+ return parseFeature(stream, null);
+ }
+
+ /**
+ * Creates and populates a default feature from stream.
+ * The parser assumes the stream contains a default feature manifest
+ * (feature.xml) as documented by the platform.
+ *
+ * @param stream feature stream
+ * @param location feature location
+ * @return populated feature model
+ * @exception CoreException
+ * @exception SAXException
+ * @since 3.1
+ */
+ public FeatureModel parseFeature(InputStream stream, String location)
+ throws CoreException, SAXException {
+ DefaultFeatureParser parser = new DefaultFeatureParser();
+ parser.init(this, location);
+ FeatureModel featureModel = null;
+ try {
+ featureModel = parser.parse(stream);
+ if (parser.getStatus()!=null) {
+ // some internalError were detected
+ IStatus status = parser.getStatus();
+ throw new CoreException(status);
+ }
+ } catch (IOException e) {
+ throw Utilities.newCoreException(Messages.FeatureModelFactory_ErrorAccesingFeatureStream, e);
+ }
+ return featureModel;
+ }
+
+ /**
+ * Create a default feature model.
+ *
+ * @see FeatureModel
+ * @return feature model
+ * @since 2.0
+ */
+ public FeatureModel createFeatureModel() {
+ return new FeatureModel();
+ }
+
+ /**
+ * Create a default included feature reference model.
+ *
+ * @see IncludedFeatureReferenceModel
+ * @return feature model
+ * @since 2.1
+ */
+ public IncludedFeatureReferenceModel createIncludedFeatureReferenceModel() {
+ return new IncludedFeatureReferenceModel();
+ }
+
+
+ /**
+ * Create a default install handler model.
+ *
+ * @see InstallHandlerEntryModel
+ * @return install handler entry model
+ * @since 2.0
+ */
+ public InstallHandlerEntryModel createInstallHandlerEntryModel() {
+ return new InstallHandlerEntryModel();
+ }
+
+ /**
+ * Create a default import dependency model.
+ *
+ * @see ImportModel
+ * @return import dependency model
+ * @since 2.0
+ */
+ public ImportModel createImportModel() {
+ return new ImportModel();
+ }
+
+ /**
+ * Create a default plug-in entry model.
+ *
+ * @see PluginEntryModel
+ * @return plug-in entry model
+ * @since 2.0
+ */
+ public PluginEntryModel createPluginEntryModel() {
+ return new PluginEntryModel();
+ }
+
+ /**
+ * Create a default non-plug-in entry model.
+ *
+ * @see NonPluginEntryModel
+ * @return non-plug-in entry model
+ * @since 2.0
+ */
+ public NonPluginEntryModel createNonPluginEntryModel() {
+ return new NonPluginEntryModel();
+ }
+
+ /**
+ * Create a default annotated URL model.
+ *
+ * @see URLEntryModel
+ * @return annotated URL model
+ * @since 2.0
+ */
+ public URLEntryModel createURLEntryModel() {
+ return new URLEntryModel();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/FeatureReferenceModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/FeatureReferenceModel.java
new file mode 100644
index 0000000..3536dc0
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/FeatureReferenceModel.java
@@ -0,0 +1,427 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * James D Miles (IBM Corp.) - bug 191783, NullPointerException in FeatureDownloader
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.update.core.Site;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+
+/**
+ * Feature reference model object.
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead instantiate or subclass the provided
+ * concrete implementation of this model.
+ * </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>
+ * @see org.eclipse.update.core.FeatureReference
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class FeatureReferenceModel extends ModelObject {
+
+ private String type;
+ private URL url;
+ private String urlString;
+ private String featureId;
+ private String featureVersion;
+ private SiteModel site;
+ private String label;
+ private String localizedLabel;
+
+ // performance
+ private URL bundleURL;
+ private URL base;
+ private boolean resolved = false;
+ private String os;
+ private String ws;
+ private String nl;
+ private String arch;
+ private String patch;
+
+ /**
+ * Creates an uninitialized feature reference model object.
+ *
+ * @since 2.0
+ */
+ public FeatureReferenceModel() {
+ super();
+ }
+
+ /**
+ * Constructor FeatureReferenceModel.
+ * @param ref
+ */
+ public FeatureReferenceModel(FeatureReferenceModel ref) {
+ setFeatureIdentifier(ref.getFeatureIdentifier());
+ setFeatureVersion(ref.getFeatureVersion());
+ setType(ref.getType());
+ setSiteModel(ref.getSiteModel());
+ setLabel(ref.getLabel());
+ setWS(ref.getWS());
+ setOS(ref.getOS());
+ setArch(ref.getOSArch());
+ setNL(ref.getNL());
+ }
+
+ /**
+ * Compares 2 feature reference models for equality
+ *
+ * @param object feature reference model to compare with
+ * @return <code>true</code> if the two models are equal,
+ * <code>false</code> otherwise
+ * @since 2.0
+ */
+ public boolean equals(Object object) {
+
+ if (object == null)
+ return false;
+ if (getURL() == null)
+ return false;
+
+ if (!(object instanceof FeatureReferenceModel))
+ return false;
+
+ FeatureReferenceModel f = (FeatureReferenceModel) object;
+
+ return UpdateManagerUtils.sameURL(getURL(), f.getURL());
+ }
+
+ /**
+ * Returns the referenced feature type.
+ *
+ * @return feature type, or <code>null</code> representing the default
+ * feature type for the site
+ * @since 2.0
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Returns the site model for the reference.
+ *
+ * @return site model
+ * @since 2.0
+ */
+ public SiteModel getSiteModel() {
+ return site;
+ }
+
+ /**
+ * Returns the unresolved URL string for the reference.
+ *
+ * @return url string
+ * @since 2.0
+ */
+ public String getURLString() {
+ return urlString;
+ }
+
+ /**
+ * Returns the resolved URL for the feature reference.
+ *
+ * @return url string
+ * @since 2.0
+ */
+ public URL getURL() {
+ delayedResolve();
+ return url;
+ }
+
+ /**
+ * Returns the feature identifier as a string
+ *
+ * @see org.eclipse.update.core.IFeatureReference#getVersionedIdentifier()
+ * @return feature identifier
+ * @since 2.0
+ */
+ public String getFeatureIdentifier() {
+ return featureId;
+ }
+
+ /**
+ * Returns the feature version as a string
+ *
+ * @see org.eclipse.update.core.IFeatureReference#getVersionedIdentifier()
+ * @return feature version
+ * @since 2.0
+ */
+ public String getFeatureVersion() {
+ return featureVersion;
+ }
+
+ /**
+ * Sets the referenced feature type.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param type referenced feature type
+ * @since 2.0
+ */
+ public void setType(String type) {
+ assertIsWriteable();
+ this.type = type;
+ }
+
+ /**
+ * Sets the site for the referenced.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param site site for the reference
+ * @since 2.0
+ */
+ public void setSiteModel(SiteModel site) {
+ assertIsWriteable();
+ this.site = site;
+ }
+
+ /**
+ * Sets the unresolved URL for the feature reference.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param urlString unresolved URL string
+ * @since 2.0
+ */
+ public void setURLString(String urlString) {
+ assertIsWriteable();
+ this.urlString = urlString;
+ this.url = null;
+ }
+
+ /**
+ * Sets the feature identifier.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param featureId feature identifier
+ * @since 2.0
+ */
+ public void setFeatureIdentifier(String featureId) {
+ assertIsWriteable();
+ this.featureId = featureId;
+ }
+
+ /**
+ * Sets the feature version.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param featureVersion feature version
+ * @since 2.0
+ */
+ public void setFeatureVersion(String featureVersion) {
+ assertIsWriteable();
+ this.featureVersion = featureVersion;
+ }
+
+ /**
+ * Resolve the model object.
+ * Any URL strings in the model are resolved relative to the
+ * base URL argument. Any translatable strings in the model that are
+ * specified as translation keys are localized using the supplied
+ * resource bundle.
+ *
+ * @param base URL
+ * @param bundleURL resource bundle URL
+ * @exception MalformedURLException
+ * @since 2.0
+ */
+ public void resolve(URL base,URL bundleURL) throws MalformedURLException {
+ this.base = base;
+ this.bundleURL = bundleURL;
+ }
+
+ private void delayedResolve() {
+
+ // PERF: delay resolution
+ if (resolved)
+ return;
+
+ // resolve local elements
+ localizedLabel = resolveNLString(bundleURL, label);
+ try {
+ url = resolveURL(base, bundleURL, urlString);
+ resolved = true;
+ } catch (MalformedURLException e){
+ UpdateCore.warn("",e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * @see Object#toString()
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(getClass().toString() + " :"); //$NON-NLS-1$
+ buffer.append(" at "); //$NON-NLS-1$
+ if (url != null)
+ buffer.append(url.toExternalForm());
+ return buffer.toString();
+ }
+
+ /**
+ * @see org.eclipse.update.core.model.ModelObject#getPropertyName()
+ */
+ protected String getPropertyName() {
+ return Site.SITE_FILE;
+ }
+
+ /**
+ * Retrieve the displayable label for the feature reference. If the model
+ * object has been resolved, the label is localized.
+ *
+ * @return displayable label, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getLabel() {
+ delayedResolve();
+ if (localizedLabel != null)
+ return localizedLabel;
+ else
+ return label;
+ }
+
+ /**
+ * Retrieve the non-localized displayable label for the feature reference.
+ *
+ * @return non-localized displayable label, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getLabelNonLocalized() {
+ return label;
+ }
+
+ /**
+ * Sets the label.
+ * @param label The label to set
+ */
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ /**
+ * Get optional operating system specification as a comma-separated string.
+ *
+ * @return the operating system specification string, or <code>null</code>.
+ * @since 2.1
+ */
+ public String getOS() {
+ return os;
+ }
+
+
+ /**
+ * Get optional windowing system specification as a comma-separated string.
+ *
+ * @return the windowing system specification string, or <code>null</code>.
+ * @since 2.1
+ */
+ public String getWS() {
+ return ws;
+ }
+
+
+ /**
+ * Get optional system architecture specification as a comma-separated string.
+ *
+ * @return the system architecture specification string, or <code>null</code>.
+ * @since 2.1
+ */
+ public String getOSArch() {
+ return arch;
+ }
+
+
+ /**
+ * Get optional locale specification as a comma-separated string.
+ *
+ * @return the locale specification string, or <code>null</code>.
+ * @since 2.1
+ */
+ public String getNL() {
+ return nl;
+ }
+
+ /**
+ * Sets the operating system specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param os operating system specification as a comma-separated list
+ * @since 2.1
+ */
+ public void setOS(String os) {
+ assertIsWriteable();
+ this.os = os;
+ }
+
+
+ /**
+ * Sets the windowing system specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param ws windowing system specification as a comma-separated list
+ * @since 2.1
+ */
+ public void setWS(String ws) {
+ assertIsWriteable();
+ this.ws = ws;
+ }
+
+
+ /**
+ * Sets the locale specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param nl locale specification as a comma-separated list
+ * @since 2.1
+ */
+ public void setNL(String nl) {
+ assertIsWriteable();
+ this.nl = nl;
+ }
+
+
+ /**
+ * Sets the system architecture specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param arch system architecture specification as a comma-separated list
+ * @since 2.1
+ */
+ public void setArch(String arch) {
+ assertIsWriteable();
+ this.arch = arch;
+ }
+
+ /**
+ * Returns the patch mode.
+ */
+ public String getPatch() {
+ return patch;
+ }
+
+
+ /**
+ * Sets the patch mode.
+ */
+ public void setPatch(String patch) {
+ this.patch = patch;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/ImportModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/ImportModel.java
new file mode 100644
index 0000000..29dada1
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/ImportModel.java
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+/**
+ * Plug-in dependency model object.
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead instantiate or subclass the provided
+ * concrete implementation of this model.
+ * </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>
+ * @see org.eclipse.update.core.Import
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class ImportModel extends ModelObject {
+
+ private String id;
+ private String version;
+ private String matchingIdRuleName;
+ private String matchingRuleName;
+ private boolean featureImport;
+ private boolean patch;
+ private String osArch;
+ private String ws;
+ private String os;
+ private String nl;
+
+ /**
+ * Creates a uninitialized plug-in dependency model object.
+ *
+ * @since 2.0
+ */
+ public ImportModel() {
+ super();
+ }
+
+ /**
+ * Returns the dependent plug-in identifier.
+ *
+ * @deprecated use getIdentifier() instead
+ * @return plug-in identifier, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getPluginIdentifier() {
+ return id;
+ }
+
+ /**
+ * Returns the dependent identifier.
+ *
+ * @return identifier, or <code>null</code>.
+ * @since 2.0.2
+ */
+ public String getIdentifier() {
+ return id;
+ }
+
+ /**
+ * Returns the dependent plug-in version.
+ *
+ * @deprecated use getVersion() instead
+ * @return plug-in version, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getPluginVersion() {
+ return version;
+ }
+
+ /**
+ * Returns the dependent version.
+ *
+ * @return version, or <code>null</code>.
+ * @since 2.0.2
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * Returns the dependent version matching rule name.
+ *
+ * @return matching rule name, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getMatchingRuleName() {
+ return matchingRuleName;
+ }
+
+ /**
+ * Returns the dependent id matching rule name.
+ *
+ * @return matching rule name, or <code>null</code>.
+ * @since 2.1
+ */
+ public String getMatchingIdRuleName() {
+ return matchingIdRuleName;
+ }
+
+ /**
+ * Sets the dependent plug-in identifier.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @deprecated use setIdentifier()
+ * @param pluginId dependent plug-in identifier
+ * @since 2.0
+ */
+ public void setPluginIdentifier(String pluginId) {
+ assertIsWriteable();
+ this.id = pluginId;
+ }
+
+ /**
+ * Sets the dependent plug-in version.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @deprecated use setVersion()
+ * @param pluginVersion dependent plug-in version
+ * @since 2.0
+ */
+ public void setPluginVersion(String pluginVersion) {
+ assertIsWriteable();
+ this.version = pluginVersion;
+ }
+
+ /**
+ * Sets the dependent identifier.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param id dependent identifier
+ * @since 2.0.2
+ */
+ public void setIdentifier(String id) {
+ assertIsWriteable();
+ this.id = id;
+ }
+
+ /**
+ * Sets the dependent version.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param version dependent version
+ * @since 2.0.2
+ */
+ public void setVersion(String version) {
+ assertIsWriteable();
+ this.version = version;
+ }
+
+ /**
+ * Sets the dependent version matching rule name.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param matchingRuleName dependent version matching rule.
+ * @since 2.0
+ */
+ public void setMatchingRuleName(String matchingRuleName) {
+ assertIsWriteable();
+ this.matchingRuleName = matchingRuleName;
+ }
+ /**
+ * Sets the dependent id matching rule name.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param matchingIdRuleName dependent id matching rule.
+ * @since 2.1
+ */
+ public void setMatchingIdRuleName(String matchingIdRuleName) {
+ assertIsWriteable();
+ this.matchingIdRuleName = matchingIdRuleName;
+ }
+ /**
+ * Returns the isFeatureImport.
+ * @return boolean
+ */
+ public boolean isFeatureImport() {
+ return featureImport;
+ }
+
+ /**
+ * Sets the featureImport.
+ * @param featureImport The featureImport to set
+ */
+ public void setFeatureImport(boolean featureImport) {
+ this.featureImport = featureImport;
+ }
+
+ /**
+ * Returns the patch mode.
+ */
+ public boolean isPatch() {
+ return patch;
+ }
+
+ /**
+ * Sets the patch mode.
+ */
+ public void setPatch(boolean patch) {
+ this.patch = patch;
+ }
+ /**
+ * Returns the os.
+ * @return String
+ */
+ public String getOS() {
+ return os;
+ }
+
+ /**
+ * Returns the osArch.
+ * @return String
+ */
+ public String getOSArch() {
+ return osArch;
+ }
+
+ /**
+ * Returns the ws.
+ * @return String
+ */
+ public String getWS() {
+ return ws;
+ }
+
+ /**
+ * Sets the os.
+ * @param os The os to set
+ */
+ public void setOS(String os) {
+ this.os = os;
+ }
+
+ /**
+ * Sets the osArch.
+ * @param osArch The osArch to set
+ */
+ public void setOSArch(String osArch) {
+ this.osArch = osArch;
+ }
+
+ /**
+ * Sets the ws.
+ * @param ws The ws to set
+ */
+ public void setWS(String ws) {
+ this.ws = ws;
+ }
+
+ /**
+ * Returns the nl.
+ * @return String
+ */
+ public String getNL() {
+ return nl;
+ }
+
+ /**
+ * Sets the nl.
+ * @param nl The nl to set
+ */
+ public void setNL(String nl) {
+ this.nl = nl;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/IncludedFeatureReferenceModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/IncludedFeatureReferenceModel.java
new file mode 100644
index 0000000..a2cce0a
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/IncludedFeatureReferenceModel.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+import org.eclipse.update.core.FeatureReference;
+import org.eclipse.update.core.IFeatureReference;
+import org.eclipse.update.core.IImport;
+import org.eclipse.update.core.IIncludedFeatureReference;
+import org.eclipse.update.core.IUpdateConstants;
+
+/**
+ * Included Feature reference model object.
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead instantiate or subclass the provided
+ * concrete implementation of this model.
+ * </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>
+ * @see org.eclipse.update.core.IncludedFeatureReference
+ * @since 2.1
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class IncludedFeatureReferenceModel extends FeatureReference {
+
+ // since 2.0.2
+ private boolean isOptional;
+ private int searchLocation;
+
+ // These are already defined by FeatureReferenceModel, we don't need to duplicate them here
+// // since 2.1
+// private String os;
+// private String ws;
+// private String arch;
+// private String nl;
+//
+ /**
+ * Construct a included feature reference
+ *
+ * @since 2.1
+ */
+ public IncludedFeatureReferenceModel() {
+ super();
+ isOptional(false);
+ setSearchLocation(IUpdateConstants.SEARCH_ROOT);
+ }
+
+
+
+ /**
+ * Construct a included feature reference model
+ *
+ * @param includedFeatureRef the included reference model to copy
+ * @since 2.1
+ */
+ public IncludedFeatureReferenceModel(IncludedFeatureReferenceModel includedFeatureRef) {
+ super((FeatureReferenceModel)includedFeatureRef);
+ isOptional(includedFeatureRef.isOptional());
+ setLabel(includedFeatureRef.getLabel());
+ setSearchLocation(includedFeatureRef.getSearchLocation());
+ setArch(includedFeatureRef.getOSArch());
+ setWS(includedFeatureRef.getWS());
+ setOS(includedFeatureRef.getOS());
+ setNL(includedFeatureRef.getNL());
+ setPatch(includedFeatureRef.getPatch());
+ }
+
+ /**
+ * Constructor IncludedFeatureReferenceModel.
+ * @param featureReference
+ */
+ public IncludedFeatureReferenceModel(IFeatureReference featureReference) {
+ super((FeatureReferenceModel)featureReference);
+ if (featureReference instanceof IIncludedFeatureReference)
+ isOptional( ((IIncludedFeatureReference)featureReference).isOptional() );
+ else
+ isOptional(false);
+ setSearchLocation(IUpdateConstants.SEARCH_ROOT);
+ setLabel(getLabel());
+ }
+
+ /**
+ * Returns the matching rule for this included feature.
+ * The rule will determine the ability of the included feature to move version
+ * without causing the overall feature to appear broken.
+ *
+ * The default is <code>MATCH_PERFECT</code>
+ *
+ * @see IImport#RULE_PERFECT
+ * @see IImport#RULE_EQUIVALENT
+ * @see IImport#RULE_COMPATIBLE
+ * @see IImport#RULE_GREATER_OR_EQUAL
+ * @return int representation of feature matching rule.
+ * @since 2.0.2
+ * @deprecated since 3.0 included feature version is exactly specified
+ */
+ public int getMatch(){
+ return IUpdateConstants.RULE_PERFECT;
+ }
+
+ /**
+ * Returns the search location for this included feature.
+ * The location will be used to search updates for this feature.
+ *
+ * The default is <code>SEARCH_ROOT</code>
+ *
+ * @see IUpdateConstants#SEARCH_ROOT
+ * @see IUpdateConstants#SEARCH_SELF
+ * @return int representation of feature searching rule.
+ * @since 2.0.2
+ */
+
+ public int getSearchLocation(){
+ return searchLocation;
+ }
+
+
+
+ /**
+ * Returns the isOptional
+ *
+ * @return isOptional
+ * @since 2.0.1
+ */
+ public boolean isOptional() {
+ return isOptional;
+ }
+
+
+
+
+ /**
+ * Sets the isOptional.
+ * @param isOptional The isOptional to set
+ */
+ public void isOptional(boolean isOptional) {
+ this.isOptional = isOptional;
+ }
+
+ /**
+ * Sets the matchingRule.
+ * @param matchingRule The matchingRule to set
+ * @deprecated since 3.0 included feature version is exactly specified
+ */
+ public void setMatchingRule(int matchingRule) {
+ }
+
+ /**
+ * Sets the searchLocation.
+ * @param searchLocation The searchLocation to set
+ */
+ public void setSearchLocation(int searchLocation) {
+ this.searchLocation = searchLocation;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/InstallAbortedException.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/InstallAbortedException.java
new file mode 100644
index 0000000..544a934
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/InstallAbortedException.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Exception thrown when the user cancelled an installation.
+ * <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>
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class InstallAbortedException extends CoreException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct the exception indicating enclosing CoreException
+ *
+ * @since 2.0
+ */
+ public InstallAbortedException(String msg,Exception e) {
+ super(new Status(IStatus.INFO,"org.eclipse.update.core",IStatus.OK,msg,e)); //$NON-NLS-1$
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/InstallHandlerEntryModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/InstallHandlerEntryModel.java
new file mode 100644
index 0000000..ea22ec7
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/InstallHandlerEntryModel.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Install handler entry model object.
+ * An object which represents the definition of a custom install handler
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead instantiate or subclass the provided
+ * concrete implementation of this model.
+ * </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>
+ * @see org.eclipse.update.core.InstallHandlerEntry
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class InstallHandlerEntryModel extends ModelObject {
+
+ private String urlString;
+ private URL url;
+ private String library;
+ private String name;
+
+ /**
+ * Creates a uninitialized install handler entry model object.
+ *
+ * @since 2.0
+ */
+ public InstallHandlerEntryModel() {
+ super();
+ }
+
+ /**
+ * Returns the URL string used for browser-triggered installation handling.
+ *
+ * @return url string or <code>null</code>
+ * @since 2.0
+ */
+ public String getURLString() {
+ return urlString;
+ }
+
+ /**
+ * Returns the resolved URL used for browser-triggered installation handling.
+ *
+ * @return url, or <code>null</code>
+ * @since 2.0
+ */
+ public URL getURL() {
+ return url;
+ }
+
+ /**
+ * Returns the name of the custom installer library.
+ *
+ * @return library path, or <code>null</code>
+ * @since 2.0
+ */
+ public String getLibrary() {
+ return library;
+ }
+
+ /**
+ * Returns the name of the custom installer.
+ *
+ * @return handler name, or <code>null</code>
+ * @since 2.0
+ */
+ public String getHandlerName() {
+ return name;
+ }
+
+ /**
+ * Sets URL string used for browser-triggered installation handling.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param urlString trigget page URL string, may be <code>null</code>.
+ * @since 2.0
+ */
+ public void setURLString(String urlString) {
+ assertIsWriteable();
+ this.urlString = urlString;
+ this.url = null;
+ }
+
+ /**
+ * Sets the custom install handler library name.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param library name, may be <code>null</code>.
+ * @since 2.0
+ */
+ public void setLibrary(String library) {
+ assertIsWriteable();
+ this.library = library;
+ }
+
+ /**
+ * Sets the name of the custom install handler.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param name name of the install handler, may be <code>null</code>.
+ * @since 2.0
+ */
+ public void setHandlerName(String name) {
+ assertIsWriteable();
+ this.name = name;
+ }
+
+ /**
+ * Resolve the model object.
+ * Any URL strings in the model are resolved relative to the
+ * base URL argument. Any translatable strings in the model that are
+ * specified as translation keys are localized using the supplied
+ * resource bundle.
+ *
+ * @param base URL
+ * @param bundleURL resource bundle URL
+ * @exception MalformedURLException
+ * @since 2.0
+ */
+ public void resolve(URL base,URL bundleURL)
+ throws MalformedURLException {
+ // resolve local elements
+ url = resolveURL(base,bundleURL, urlString);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/InvalidSiteTypeException.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/InvalidSiteTypeException.java
new file mode 100644
index 0000000..50c9214
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/InvalidSiteTypeException.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+/**
+ * Exception thrown when the type of the site discovered in the site manifest
+ * does not correspond to the type expected by the concrete site factory.
+ *
+ * <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>
+ * @see org.eclipse.update.core.model.SiteModelFactory#canParseSiteType(String)
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class InvalidSiteTypeException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+ private String newSiteType;
+
+ /**
+ * Construct the exception indicating the detected site type
+ *
+ * @since 2.0
+ */
+ public InvalidSiteTypeException(String newType) {
+ super();
+ newSiteType = newType;
+ }
+
+ /**
+ * Returns the site type detected in the parsed site manifest
+ *
+ * @return site type
+ * @since 2.0
+ */
+ public String getNewType() {
+ return newSiteType;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/ModelObject.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/ModelObject.java
new file mode 100644
index 0000000..9b55b02
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/ModelObject.java
@@ -0,0 +1,399 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+import java.lang.reflect.Array;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.update.core.Feature;
+import org.eclipse.update.core.SiteManager;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+
+/**
+ * Root model object. Extended by all model objects.
+ * <p>
+ * This class cannot be instantiated and must be subclassed.
+ * </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>
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public abstract class ModelObject extends PlatformObject {
+
+ private boolean readOnly = false;
+
+ private static final String KEY_PREFIX = "%"; //$NON-NLS-1$
+ private static final String KEY_DOUBLE_PREFIX = KEY_PREFIX + KEY_PREFIX;
+
+ private static Map bundles;
+
+ /**
+ * Creates a base model object.
+ *
+ * @since 2.0
+ */
+ protected ModelObject() {
+ }
+
+ /**
+ * Checks that this model object is writeable. A runtime exception
+ * is thrown if it is not.
+ *
+ * @since 2.0
+ */
+ protected final void assertIsWriteable() {
+ Assert.isTrue(!isReadOnly(), Messages.ModelObject_ModelReadOnly);
+ }
+
+ /**
+ * Sets this model object and all of its descendents to be read-only.
+ * Subclasses may extend this implementation.
+ *
+ * @see #isReadOnly
+ * @since 2.0
+ */
+ public void markReadOnly() {
+ readOnly = true;
+ }
+
+ /**
+ * Returns whether or not this model object is read-only.
+ *
+ * @return <code>true</code> if this model object is read-only,
+ * <code>false</code> otherwise
+ * @see #markReadOnly
+ * @since 2.0
+ */
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ /**
+ * Delegate setting of read-only
+ *
+ * @param o object to delegate to. Must be of type ModelObject.
+ * @see #isReadOnly
+ * @since 2.0
+ */
+ protected void markReferenceReadOnly(ModelObject o) {
+ if (o == null)
+ return;
+ o.markReadOnly();
+ }
+
+ /**
+ * Delegate setting of read-only
+ *
+ * @param o object array to delegate to. Each element must be of type ModelObject.
+ * @see #isReadOnly
+ * @since 2.0
+ */
+ protected void markListReferenceReadOnly(ModelObject[] o) {
+ if (o == null)
+ return;
+ for (int i = 0; i < o.length; i++) {
+ o[i].markReadOnly();
+ }
+ }
+
+ /**
+ * Resolve the model element. This method allows any relative URL strings
+ * to be resolved to actual URL. It also allows any translatable strings
+ * to be localized.
+ *
+ * Subclasses need to override this method to perform the actual resolution.
+ * @param base base URL.
+ * @param bundleURL resource bundle URL.
+ * @exception MalformedURLException
+ * @since 2.0
+ */
+ public void resolve(URL base, URL bundleURL) throws MalformedURLException {
+ return;
+ }
+
+ /**
+ * Delegate resolution to referenced model
+ *
+ * @param o object to delegate to. Must be of type ModelObject.
+ * @param url base URL.
+ * @param bundleURL resource bundle URL.
+ * @exception MalformedURLException
+ * @since 2.0
+ */
+ protected void resolveReference(ModelObject o, URL url, URL bundleURL) throws MalformedURLException {
+ if (o == null)
+ return;
+ o.resolve(url, bundleURL);
+ }
+
+ /**
+ * Delegate resolution to list of referenced models
+ *
+ * @param o object array to delegate to. Each element must be of type ModelObject.
+ * @param url base URL.
+ * @param bundleURL resource bundle URL.
+ * @exception MalformedURLException
+ * @since 2.0
+ */
+ protected void resolveListReference(ModelObject[] o, URL url, URL bundleURL) throws MalformedURLException {
+ if (o == null)
+ return;
+ for (int i = 0; i < o.length; i++) {
+ o[i].resolve(url, bundleURL);
+ }
+ }
+
+ /**
+ * Resolve a URL based on context
+ *
+ * @param context base URL.
+ * @param bundleURL resource bundle URL.
+ * @param urlString url string from model.
+ * @return URL, or <code>null</code>.
+ * @exception MalformedURLException
+ * @since 2.0
+ */
+ protected URL resolveURL(URL context, URL bundleURL, String urlString) throws MalformedURLException {
+
+ // URL string was not specified
+ if (urlString == null || urlString.trim().equals("")) //$NON-NLS-1$
+ return null;
+
+ // check to see if we have NL-sensitive URL
+ String resolvedUrlString = resolveNLString(bundleURL, urlString);
+
+ resolvedUrlString = resolvePlatfromConfiguration(resolvedUrlString);
+
+ // if we don't have a base url, use only the supplied string
+ if (context == null)
+ return new URL(resolvedUrlString);
+
+ // otherwise return new URL in context of base URL
+ return new URL(context, resolvedUrlString);
+ }
+ /**
+ * Resolves the URL based on platfrom Configuration
+ * $os$\$ws$\license.txt will become
+ * win32\win32\license.txt on a system where os=win32 and ws=win32
+ *
+ * @param resolvedUrlString
+ * @return String
+ */
+ private String resolvePlatfromConfiguration(String resolvedUrlString) {
+ int osIndex = resolvedUrlString.indexOf("$os$"); //$NON-NLS-1$
+ if (osIndex != -1)
+ return getExtendedString(resolvedUrlString);
+
+ int wsIndex = resolvedUrlString.indexOf("$ws$"); //$NON-NLS-1$
+ if (wsIndex != -1)
+ return getExtendedString(resolvedUrlString);
+
+ int nlIndex = resolvedUrlString.indexOf("$nl$"); //$NON-NLS-1$
+ if (nlIndex != -1)
+ return getExtendedString(resolvedUrlString);
+
+ int archIndex = resolvedUrlString.indexOf("$arch$"); //$NON-NLS-1$
+ if (archIndex != -1)
+ return getExtendedString(resolvedUrlString);
+
+ return resolvedUrlString;
+ }
+
+ private String getExtendedString(String resolvedUrlString) {
+ IPath path = new Path(resolvedUrlString);
+ path = getExpandedPath(path);
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_WARNINGS) {
+ UpdateCore.warn("Resolved :" + resolvedUrlString + " as:" + path.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ return path.toOSString();
+ }
+
+ private IPath getExpandedPath(IPath path) {
+ String first = path.segment(0);
+ if (first != null) {
+ IPath rest = getExpandedPath(path.removeFirstSegments(1));
+ if (first.equals("$ws$")) { //$NON-NLS-1$
+ path = new Path(SiteManager.getWS()).append(rest);
+ } else if (first.equals("$os$")) { //$NON-NLS-1$
+ path = new Path(SiteManager.getOS()).append(rest);
+ } else if (first.equals("$nl$")) { //$NON-NLS-1$
+ path = new Path(SiteManager.getNL()).append(rest);
+ } else if (first.equals("$arch$")) { //$NON-NLS-1$
+ path = new Path(SiteManager.getOSArch()).append(rest);
+ }
+ }
+ return path;
+ }
+
+ /**
+ * Returns a resource string corresponding to the given argument
+ * value and bundle.
+ * If the argument value specifies a resource key, the string
+ * is looked up in the given resource bundle. If the argument does not
+ * specify a valid key, the argument itself is returned as the
+ * resource string. The key lookup is performed against the
+ * specified resource bundle. If a resource string
+ * corresponding to the key is not found in the resource bundle
+ * the key value, or any default text following the key in the
+ * argument value is returned as the resource string.
+ * A key is identified as a string begining with the "%" character.
+ * Note that the "%" character is stripped off prior to lookup
+ * in the resource bundle.
+ * <p>
+ * For example, assume resource bundle plugin.properties contains
+ * name = Project Name
+ * <pre>
+ * resolveNLString(b,"Hello World") returns "Hello World"</li>
+ * resolveNLString(b,"%name") returns "Project Name"</li>
+ * resolveNLString(b,"%name Hello World") returns "Project Name"</li>
+ * resolveNLString(b,"%abcd Hello World") returns "Hello World"</li>
+ * resolveNLString(b,"%abcd") returns "%abcd"</li>
+ * resolveNLString(b,"%%name") returns "%name"</li>
+ * </pre>
+ * </p>
+ *
+ * @param bundleURL resource bundle url.
+ * @param string translatable string from model
+ * @return string, or <code>null</code>
+ * @since 2.0
+ */
+ protected String resolveNLString(URL bundleURL, String string) {
+
+ if (string == null)
+ return null;
+
+ String s = string.trim();
+
+ if (s.equals("")) //$NON-NLS-1$
+ return string;
+
+ if (!s.startsWith(KEY_PREFIX))
+ return string;
+
+ if (s.startsWith(KEY_DOUBLE_PREFIX))
+ return s.substring(1);
+
+ int ix = s.indexOf(" "); //$NON-NLS-1$
+ String key = ix == -1 ? s : s.substring(0, ix);
+ String dflt = ix == -1 ? s : s.substring(ix + 1);
+
+ ResourceBundle b = getResourceBundle(bundleURL);
+
+ if (b == null)
+ return dflt;
+
+ try {
+ return b.getString(key.substring(1));
+ } catch (MissingResourceException e) {
+ return dflt;
+ }
+ }
+
+ /**
+ * Returns a concrete array type for the elements of the specified
+ * list. The method assumes all the elements of the list are the same
+ * concrete type as the first element in the list.
+ *
+ * @param l list
+ * @return concrete array type, or <code>null</code> if the array type
+ * could not be determined (the list is <code>null</code> or empty)
+ * @since 2.0
+ */
+ protected Object[] arrayTypeFor(List l) {
+ if (l == null || l.size() == 0)
+ return null;
+ return (Object[]) Array.newInstance(l.get(0).getClass(), 0);
+ }
+
+ /**
+ * Returns a concrete array type for the elements of the specified
+ * set. The method assumes all the elements of the set are the same
+ * concrete type as the first element in the set.
+ *
+ * @param s set
+ * @return concrete array type, or <code>null</code> if the array type
+ * could not be determined (the set is <code>null</code> or empty)
+ * @since 2.0
+ */
+ protected Object[] arrayTypeFor(Set s) {
+ if (s == null || s.size() == 0)
+ return null;
+ Iterator i = s.iterator();
+ return (Object[]) Array.newInstance(i.next().getClass(), 0);
+ }
+
+ /**
+ * Helper method to access resouce bundle for feature. The default
+ * implementation attempts to load the appropriately localized
+ * feature.properties file.
+ *
+ * @param url base URL used to load the resource bundle.
+ * @return resource bundle, or <code>null</code>.
+ * @since 2.0
+ */
+ protected ResourceBundle getResourceBundle(URL url) {
+
+ if (url == null)
+ return null;
+
+ if (bundles == null) {
+ bundles = new HashMap();
+ } else {
+ ResourceBundle bundle = (ResourceBundle) bundles.get(url.toExternalForm());
+ if (bundle != null)
+ return bundle;
+ }
+
+ ResourceBundle bundle = null;
+ try {
+ url = UpdateManagerUtils.asDirectoryURL(url);
+ ClassLoader l = new URLClassLoader(new URL[] { url }, null);
+ bundle = ResourceBundle.getBundle(getPropertyName(), Locale.getDefault(), l);
+ bundles.put(url.toExternalForm(), bundle);
+ } catch (MissingResourceException e) {
+ UpdateCore.warn(e.getLocalizedMessage() + ":" + url.toExternalForm()); //$NON-NLS-1$
+ } catch (MalformedURLException e) {
+ UpdateCore.warn(e.getLocalizedMessage());
+ }
+ return bundle;
+ }
+
+ /**
+ * Method getPropertyName.
+ * @return String
+ */
+ protected String getPropertyName() {
+ return Feature.FEATURE_FILE;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/NonPluginEntryModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/NonPluginEntryModel.java
new file mode 100644
index 0000000..44ec8f5
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/NonPluginEntryModel.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+/**
+ * Non-plug-in entry model object.
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead instantiate or subclass the provided
+ * concrete implementation of this model.
+ * </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>
+ * @see org.eclipse.update.core.NonPluginEntry
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class NonPluginEntryModel extends ContentEntryModel {
+
+ private String id = null;
+
+ /**
+ * Creates a uninitialised non-plug-in entry model object.
+ *
+ * @since 2.0
+ */
+ public NonPluginEntryModel() {
+ super();
+ }
+
+ /**
+ * Returns the entry identifier.
+ *
+ * @return entry identifier, or <code>null</code>
+ * @since 2.0
+ */
+ public String getIdentifier() {
+ return id;
+ }
+
+ /**
+ * Sets the entry identifier.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param id entry identifier.
+ * @since 2.0
+ */
+ public void setIdentifier(String id) {
+ assertIsWriteable();
+ this.id = id;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/PluginEntryModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/PluginEntryModel.java
new file mode 100644
index 0000000..b78c1dc
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/PluginEntryModel.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+
+/**
+ * Plug-in entry model object.
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead instantiate or subclass the provided
+ * concrete implementation of this model.
+ * </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>
+ * @see org.eclipse.update.core.PluginEntry
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class PluginEntryModel extends ContentEntryModel {
+
+ private String pluginId;
+ private String pluginVersion;
+ private boolean isFragment = false;
+ private boolean unpack = true;
+
+ /**
+ * Creates a uninitialized plug-in entry model object.
+ *
+ * @since 2.0
+ */
+ public PluginEntryModel() {
+ super();
+ }
+
+ /**
+ * Compares two plug-in models for equality
+ *
+ * @param obj other model to compare to
+ * @return <code>true</code> if the models are equal, <code>false</code> otherwise
+ * @since 2.0
+ */
+ public boolean equals(Object obj) {
+ if (!(obj instanceof PluginEntryModel))
+ return false;
+ PluginEntryModel model = (PluginEntryModel) obj;
+
+ return (
+ (getPluginIdentifier().equals(model.getPluginIdentifier()))
+ && (getPluginVersion().equals(model.getPluginVersion()))
+ && (isFragment() == model.isFragment()));
+ }
+
+ /**
+ * Returns the plug-in identifier for this entry.
+ *
+ * @return the plug-in identifier, or <code>null</code>
+ * @since 2.0
+ */
+ public String getPluginIdentifier() {
+ return pluginId;
+ }
+
+ /**
+ * Returns the plug-in version for this entry.
+ *
+ * @return the plug-in version, or <code>null</code>
+ * @since 2.0
+ */
+ public String getPluginVersion() {
+ return pluginVersion;
+ }
+
+ /**
+ * Indicates whether the entry describes a full plug-in, or
+ * a plug-in fragment.
+ *
+ * @return <code>true</code> if the entry is a plug-in fragment,
+ * <code>false</code> if the entry is a plug-in
+ * @since 2.0
+ */
+ public boolean isFragment() {
+ return isFragment;
+ }
+
+ /**
+ * Sets the entry plug-in identifier.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param pluginId the entry identifier.
+ * @since 2.0
+ */
+ public void setPluginIdentifier(String pluginId) {
+ assertIsWriteable();
+ this.pluginId = pluginId;
+ }
+
+ /**
+ * Sets the entry plug-in version.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param pluginVersion the entry version.
+ * @since 2.0
+ */
+ public void setPluginVersion(String pluginVersion) {
+ assertIsWriteable();
+ this.pluginVersion = pluginVersion;
+ }
+
+ /**
+ * Indicates whether this entry represents a fragment or plug-in.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param isFragment fragment setting
+ * @since 2.0
+ */
+ public void isFragment(boolean isFragment) {
+ assertIsWriteable();
+ this.isFragment = isFragment;
+ }
+
+ /**
+ * @return Indicates whether plugin should be unpacked during installation
+ * or can run from a jar
+ * @since 3.0
+ */
+ public boolean isUnpack() {
+ // TODO this is a candidate for IPluginEntry API
+ return unpack;
+ }
+ /**
+ * @param unpack Sets whether plugin should be unpacked during installation
+ * or can run from a jar
+ * @since 3.0
+ *
+ */
+ public void setUnpack(boolean unpack) {
+ // TODO this is a candidate for IPluginEntry API
+ assertIsWriteable();
+ this.unpack = unpack;
+ }
+
+ /**
+ * @see Object#toString()
+ */
+ public String toString() {
+ String msg = (getPluginIdentifier()!=null)?getPluginIdentifier().toString():""; //$NON-NLS-1$
+ msg += getPluginVersion()!=null?" "+getPluginVersion().toString():""; //$NON-NLS-1$ //$NON-NLS-2$
+ msg += isFragment()?" fragment":" plugin"; //$NON-NLS-1$ //$NON-NLS-2$
+ return msg;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/SiteModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/SiteModel.java
new file mode 100644
index 0000000..bd8f17c
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/SiteModel.java
@@ -0,0 +1,465 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.update.core.Site;
+import org.eclipse.update.core.SiteFeatureReferenceModel;
+import org.eclipse.update.internal.core.ExtendedSite;
+import org.eclipse.update.internal.core.SiteURLFactory;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+import org.eclipse.update.internal.model.ConfiguredSiteModel;
+
+/**
+ * Site model object.
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead instantiate or subclass the provided
+ * concrete implementation of this model.
+ * </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>
+ * @see org.eclipse.update.core.Site
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class SiteModel extends ModelObject {
+
+ private String type;
+ private URLEntryModel description;
+ private List /*of FeatureReferenceModel*/ featureReferences;
+ private List /*of ArchiveReferenceModel*/ archiveReferences;
+ private Set /*of CategoryModel*/ categories;
+ private List /* of URLEntryModel */ mirrors;
+ private String locationURLString;
+ private URL locationURL;
+ private String mirrorsURLString;
+ private ConfiguredSiteModel configuredSiteModel;
+
+ /**
+ * Creates an uninitialized site model object.
+ *
+ * @since 2.0
+ */
+ public SiteModel() {
+ super();
+ }
+
+ /**
+ * Returns the site type.
+ *
+ * @return site type, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Returns the site description.
+ *
+ * @return site description, or <code>null</code>.
+ * @since 2.0
+ */
+ public URLEntryModel getDescriptionModel() {
+ return description;
+ }
+
+ /**
+ * Returns an array of feature reference models on this site.
+ *
+ * @return an array of feature reference models, or an empty array.
+ * @since 2.0
+ */
+ public SiteFeatureReferenceModel[] getFeatureReferenceModels() {
+ if (featureReferences == null || featureReferences.size() == 0)
+ return new SiteFeatureReferenceModel[0];
+
+ return (SiteFeatureReferenceModel[]) featureReferences.toArray(arrayTypeFor(featureReferences));
+ }
+
+ /**
+ * Returns an array of plug-in and non-plug-in archive reference models
+ * on this site
+ *
+ * @return an array of archive reference models, or an empty array if there are
+ * no archives known to this site.
+ * @since 2.0
+ */
+ public ArchiveReferenceModel[] getArchiveReferenceModels() {
+ if (archiveReferences == null || archiveReferences.size() == 0)
+ return new ArchiveReferenceModel[0];
+
+ return (ArchiveReferenceModel[]) archiveReferences.toArray(arrayTypeFor(archiveReferences));
+ }
+
+ /**
+ * Returns an array of category models for this site.
+ *
+ * @return array of site category models, or an empty array.
+ * @since 2.0
+ */
+ public CategoryModel[] getCategoryModels() {
+ if (categories == null || categories.size()==0)
+ return new CategoryModel[0];
+
+ return (CategoryModel[]) categories.toArray(arrayTypeFor(categories));
+ }
+
+ /**
+ * Returns the unresolved URL string for the site.
+ *
+ * @return url string, or <code>null</code>
+ * @since 2.0
+ */
+ public String getLocationURLString() {
+ return locationURLString;
+ }
+
+ /**
+ * Returns the resolved URL for the site.
+ *
+ * @return url, or <code>null</code>
+ * @since 2.0
+ */
+ public URL getLocationURL() {
+ return locationURL;
+ }
+
+ /**
+ * Sets the site type.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param type site type
+ * @since 2.0
+ */
+ public void setType(String type) {
+ assertIsWriteable();
+ this.type = type;
+ }
+
+ /**
+ * Sets the site description.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param description site description
+ * @since 2.0
+ */
+ public void setDescriptionModel(URLEntryModel description) {
+ assertIsWriteable();
+ this.description = description;
+ }
+
+ /**
+ * Sets the feature references for this site.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param featureReferences an array of feature reference models
+ * @since 2.0
+ */
+ public void setFeatureReferenceModels(FeatureReferenceModel[] featureReferences) {
+ assertIsWriteable();
+ if (featureReferences == null)
+ this.featureReferences = null;
+ else
+ this.featureReferences = new ArrayList(Arrays.asList(featureReferences));
+ }
+
+ /**
+ * Sets the archive references for this site.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param archiveReferences an array of archive reference models
+ * @since 2.0
+ */
+ public void setArchiveReferenceModels(ArchiveReferenceModel[] archiveReferences) {
+ assertIsWriteable();
+ if (archiveReferences == null)
+ this.archiveReferences = null;
+ else
+ this.archiveReferences = new ArrayList(Arrays.asList(archiveReferences));
+ }
+
+ /**
+ * Sets the site categories.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param categories an array of category models
+ * @since 2.0
+ */
+ public void setCategoryModels(CategoryModel[] categories) {
+ assertIsWriteable();
+ if (categories == null)
+ this.categories = null;
+ else {
+ this.categories = new TreeSet(CategoryModel.getComparator());
+ this.categories.addAll(Arrays.asList(categories));
+ }
+ }
+
+ /**
+ * Sets the unresolved URL for the site.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param locationURLString url for the site (as a string)
+ * @since 2.0
+ */
+ public void setLocationURLString(String locationURLString) {
+ assertIsWriteable();
+ this.locationURLString = locationURLString;
+ }
+
+ /**
+ * Adds a feature reference model to site.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param featureReference feature reference model
+ * @since 2.0
+ */
+ public void addFeatureReferenceModel(SiteFeatureReferenceModel featureReference) {
+ assertIsWriteable();
+ if (this.featureReferences == null)
+ this.featureReferences = new ArrayList();
+ // PERF: do not check if already present
+ //if (!this.featureReferences.contains(featureReference))
+ this.featureReferences.add(featureReference);
+ }
+
+ /**
+ * Adds an archive reference model to site.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param archiveReference archive reference model
+ * @since 2.0
+ */
+ public void addArchiveReferenceModel(ArchiveReferenceModel archiveReference) {
+ assertIsWriteable();
+ if (this.archiveReferences == null)
+ this.archiveReferences = new ArrayList();
+ if (!this.archiveReferences.contains(archiveReference))
+ this.archiveReferences.add(archiveReference);
+ }
+
+ /**
+ * Adds a category model to site.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param category category model
+ * @since 2.0
+ */
+ public void addCategoryModel(CategoryModel category) {
+ assertIsWriteable();
+ if (this.categories == null)
+ this.categories = new TreeSet(CategoryModel.getComparator());
+ if (!this.categories.contains(category))
+ this.categories.add(category);
+ }
+
+ /**
+ * Adds a mirror site.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param mirror mirror model
+ * @since 3.1
+ */
+ public void addMirrorModel(URLEntryModel mirror) {
+ assertIsWriteable();
+ if (this.mirrors == null)
+ this.mirrors = new ArrayList();
+ if (!this.mirrors.contains(mirror))
+ this.mirrors.add(mirror);
+ }
+
+ /**
+ * Removes a feature reference model from site.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param featureReference feature reference model
+ * @since 2.0
+ */
+ public void removeFeatureReferenceModel(FeatureReferenceModel featureReference) {
+ assertIsWriteable();
+ if (this.featureReferences != null)
+ this.featureReferences.remove(featureReference);
+ }
+
+ /**
+ * Removes an archive reference model from site.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param archiveReference archive reference model
+ * @since 2.0
+ */
+ public void removeArchiveReferenceModel(ArchiveReferenceModel archiveReference) {
+ assertIsWriteable();
+ if (this.archiveReferences != null)
+ this.archiveReferences.remove(archiveReference);
+ }
+
+ /**
+ * Removes a category model from site.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param category category model
+ * @since 2.0
+ */
+ public void removeCategoryModel(CategoryModel category) {
+ assertIsWriteable();
+ if (this.categories != null)
+ this.categories.remove(category);
+ }
+
+ /**
+ * Removes a mirror from site.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param mirror mirror to remove
+ * @since 3.1
+ */
+ public void removeMirror(URLEntryModel mirror) {
+ assertIsWriteable();
+ if (this.mirrors != null)
+ this.mirrors.remove(mirror);
+ }
+
+ /**
+ * Marks the model object as read-only.
+ *
+ * @since 2.0
+ */
+ public void markReadOnly() {
+ super.markReadOnly();
+ markReferenceReadOnly(getDescriptionModel());
+ markListReferenceReadOnly(getFeatureReferenceModels());
+ markListReferenceReadOnly(getArchiveReferenceModels());
+ markListReferenceReadOnly(getCategoryModels());
+ }
+
+ /**
+ * Resolve the model object.
+ * Any URL strings in the model are resolved relative to the
+ * base URL argument. Any translatable strings in the model that are
+ * specified as translation keys are localized using the supplied
+ * resource bundle.
+ *
+ * @param base URL
+ * @param bundleURL resource bundle URL
+ * @exception MalformedURLException
+ * @since 2.0
+ */
+ public void resolve(URL base, URL bundleURL) throws MalformedURLException {
+
+ // Archives and feature are relative to location URL
+ // if the Site element has a URL tag: see spec
+ locationURL = resolveURL(base, bundleURL, getLocationURLString());
+ if (locationURL == null)
+ locationURL = base;
+ resolveListReference(getFeatureReferenceModels(), locationURL, bundleURL);
+ resolveListReference(getArchiveReferenceModels(), locationURL, bundleURL);
+
+ resolveReference(getDescriptionModel(), base, bundleURL);
+ resolveListReference(getCategoryModels(), base, bundleURL);
+
+ URL url = resolveURL(base, bundleURL, mirrorsURLString);
+ if (url != null)
+ mirrorsURLString = url.toString();
+
+ if ( (this instanceof ExtendedSite) && ((ExtendedSite)this).isDigestExist()) {
+ ExtendedSite extendedSite = (ExtendedSite)this;
+ extendedSite.setLiteFeatures(UpdateManagerUtils.getLightFeatures(extendedSite));
+ }
+ }
+
+ /**
+ *
+ */
+ public ConfiguredSiteModel getConfiguredSiteModel() {
+ return this.configuredSiteModel;
+ }
+
+ /**
+ *
+ */
+ public void setConfiguredSiteModel(ConfiguredSiteModel configuredSiteModel) {
+ this.configuredSiteModel = configuredSiteModel;
+ }
+
+ /**
+ * @see org.eclipse.update.core.model.ModelObject#getPropertyName()
+ */
+ protected String getPropertyName() {
+ return Site.SITE_FILE;
+ }
+
+ /**
+ * Return an array of updat site mirrors
+ *
+ * @return an array of mirror entries, or an empty array.
+ * @since 3.1
+ */
+ public URLEntryModel[] getMirrorSiteEntryModels() {
+ //delayedResolve(); no delay;
+ if ( mirrors == null || mirrors.size() == 0)
+ // see if we can get mirrors from the provided url
+ if (mirrorsURLString != null)
+ doSetMirrorSiteEntryModels(DefaultSiteParser.getMirrors(mirrorsURLString, new SiteURLFactory()));
+
+ if (mirrors == null || mirrors.size() == 0)
+ return new URLEntryModel[0];
+ else
+ return (URLEntryModel[]) mirrors.toArray(arrayTypeFor(mirrors));
+ }
+
+ /**
+ * Sets additional mirror sites
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param mirrors additional update site mirrors
+ * @since 3.1
+ */
+ public void setMirrorSiteEntryModels(URLEntryModel[] mirrors) {
+ assertIsWriteable();
+ doSetMirrorSiteEntryModels(mirrors);
+ }
+
+ private void doSetMirrorSiteEntryModels(URLEntryModel[] mirrors) {
+ if (mirrors == null || mirrors.length == 0)
+ this.mirrors = null;
+ else
+ this.mirrors = new ArrayList(Arrays.asList(mirrors));
+ }
+
+ /**
+ * Sets the mirrors url. Mirror sites will then be obtained from this mirror url later.
+ * This method is complementary to setMirrorsiteEntryModels(), and only one of these
+ * methods should be called.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param mirrorsURL additional update site mirrors
+ * @since 3.1
+ */
+ public void setMirrorsURLString(String mirrorsURL) {
+ assertIsWriteable();
+ this.mirrorsURLString = mirrorsURL;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/SiteModelFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/SiteModelFactory.java
new file mode 100644
index 0000000..097884f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/SiteModelFactory.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.update.core.SiteFeatureReferenceModel;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.internal.core.Messages;
+import org.xml.sax.SAXException;
+
+/**
+ * Default site model factory.
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead subclass the provided base implementation
+ * of this factory.
+ * </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>
+ * @see org.eclipse.update.core.BaseSiteFactory
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class SiteModelFactory {
+
+ private static DefaultSiteParser parser = new DefaultSiteParser();
+
+ /**
+ * Creates a default site factory.
+ *
+ * @since 2.0
+ */
+ public SiteModelFactory() {
+ super();
+ }
+
+ /**
+ * Indicates whether this factory can handle the specified site type. This
+ * method is intended to be overridden by subclasses.
+ *
+ * @param type site type identifier
+ * @return <code>true</code> if the type can be handled, otherwise <code>false</code>
+ * @since 2.0
+ */
+ public boolean canParseSiteType(String type) {
+ // return true if type was not specified (ie. is null or empty string)
+ return (type == null || type.trim().equals("")); //$NON-NLS-1$
+ }
+
+ /**
+ * Creates and populates a default site from stream.
+ * The parser assumes the stream contains a default site manifest
+ * (site.xml) as documented by the platform.
+ *
+ * @param stream site stream
+ * @return populated site model
+ * @exception CoreException
+ * @exception InvalidSiteTypeException
+ * @since 2.0
+ */
+ public SiteModel parseSite(InputStream stream)
+ throws CoreException, InvalidSiteTypeException {
+ SiteModel result = null;
+ try {
+ parser.init(this);
+ result = parser.parse(stream);
+ if (parser.getStatus()!=null) {
+ // some internalError were detected
+ IStatus status = parser.getStatus();
+ throw new CoreException(status);
+ }
+ } catch (SAXException e) {
+ // invalid Site type
+ if (e.getException() instanceof InvalidSiteTypeException) {
+ throw (InvalidSiteTypeException) e.getException();
+ }
+
+ throw Utilities.newCoreException(Messages.SiteModelObject_ErrorParsingSiteStream,e);
+ } catch (IOException e){
+ throw Utilities.newCoreException(Messages.SiteModelObject_ErrorAccessingSiteStream,e);
+ }
+ return result;
+ }
+
+ /**
+ * Create a default site model.
+ *
+ * @see SiteModel
+ * @return site model
+ * @since 2.0
+ */
+ public SiteModel createSiteMapModel() {
+ return new SiteModel();
+ }
+
+ /**
+ * Create a default site feature reference model.
+ *
+ * @see SiteFeatureReferenceModel
+ * @return site feature reference model
+ * @since 2.0
+ */
+ public SiteFeatureReferenceModel createFeatureReferenceModel() {
+ return new SiteFeatureReferenceModel();
+ }
+
+ /**
+ * Create a default archive reference model.
+ *
+ * @see ArchiveReferenceModel
+ * @return archive reference model
+ * @since 2.0
+ */
+ public ArchiveReferenceModel createArchiveReferenceModel() {
+ return new ArchiveReferenceModel();
+ }
+
+ /**
+ * Create a default annotated URL model.
+ *
+ * @see URLEntryModel
+ * @return annotated URL model
+ * @since 2.0
+ */
+ public URLEntryModel createURLEntryModel() {
+ return new URLEntryModel();
+ }
+
+ /**
+ * Create a default category model.
+ *
+ * @see CategoryModel
+ * @return category model
+ * @since 2.0
+ */
+ public CategoryModel createSiteCategoryModel() {
+ return new CategoryModel();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/URLEntryModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/URLEntryModel.java
new file mode 100644
index 0000000..2d4f866
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/URLEntryModel.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.core.model;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.update.core.IURLEntry;
+import org.eclipse.update.internal.core.UpdateCore;
+
+/**
+ * Annotated URL model object.
+ * <p>
+ * This class may be instantiated or subclassed by clients. However, in most
+ * cases clients should instead instantiate or subclass the provided
+ * concrete implementation of this model.
+ * </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>
+ * @see org.eclipse.update.core.URLEntry
+ * @since 2.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class URLEntryModel extends ModelObject {
+
+ private String annotation;
+ private String localizedAnnotation;
+ private String urlString;
+ private URL url;
+
+ private int type = IURLEntry.UPDATE_SITE;
+
+ //performance
+ private URL bundleURL;
+ private URL base;
+ private boolean resolved=false;
+
+ /**
+ * Creates a uninitialized annotated URL model object.
+ *
+ * @since 2.0
+ */
+ public URLEntryModel() {
+ super();
+ }
+
+ /**
+ * Returns the url annotation. If the model object has been resolved,
+ * the annotation is localized.
+ *
+ * @return url annotation, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getAnnotation() {
+ delayedResolve();
+ if (localizedAnnotation != null)
+ return localizedAnnotation;
+ else
+ return annotation;
+ }
+
+ /**
+ * returns the non-localized url annotation.
+ *
+ * @return non-localized url annotation, or <code>null</code>.
+ * @since 2.0
+ */
+ public String getAnnotationNonLocalized() {
+ return annotation;
+ }
+
+ /**
+ * Returns the unresolved url string.
+ *
+ * @return url string, or <code>null</code>
+ * @since 2.0
+ */
+ public String getURLString() {
+ delayedResolve();
+ return urlString;
+ }
+
+ /**
+ * Returns the resolved URL.
+ *
+ * @return url, or <code>null</code>
+ * @since 2.0
+ */
+ public URL getURL() {
+ delayedResolve();
+ return url;
+ }
+
+ /**
+ * Sets the annotation.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param annotation annotation
+ * @since 2.0
+ */
+ public void setAnnotation(String annotation) {
+ assertIsWriteable();
+ this.annotation = annotation;
+ this.localizedAnnotation = null;
+ }
+
+ /**
+ * Sets the url string
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param urlString url string
+ * @since 2.0
+ */
+ public void setURLString(String urlString) {
+ assertIsWriteable();
+ this.urlString = urlString;
+ this.url = null;
+ }
+
+ /**
+ * Resolve the model object.
+ * Any URL strings in the model are resolved relative to the
+ * base URL argument. Any translatable strings in the model that are
+ * specified as translation keys are localized using the supplied
+ * resource bundle.
+ *
+ * @param base URL
+ * @param bundleURL resource bundle url
+ * @exception MalformedURLException
+ * @since 2.0
+ */
+ public void resolve(URL base, URL bundleURL) throws MalformedURLException {
+ this.base = base;
+ this.bundleURL = bundleURL;
+ }
+
+
+ private void delayedResolve() {
+
+ //PERF: delay resolution
+ if (resolved)return;
+
+ resolved= true;
+ // resolve local elements
+ localizedAnnotation = resolveNLString(bundleURL, annotation);
+ try {
+ url = resolveURL(base,bundleURL, urlString);
+ } catch (MalformedURLException e){
+ UpdateCore.warn("",e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the specified type.
+ *
+ * @since 2.1
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * Method setType.
+ * @param i
+ */
+ public void setType(int i) {
+ type = i;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/model/package.html b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/package.html
new file mode 100644
index 0000000..03886d3
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/model/package.html
@@ -0,0 +1,27 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="Author" content="IBM">
+ <meta name="GENERATOR" content="Mozilla/4.72 [en] (Windows NT 5.0; U) [Netscape]">
+ <title>Package-level Javadoc</title>
+</head>
+<body>
+Provides model support for extending the base installation
+and update services.
+<h2>
+Package Specification</h2>
+This package provides a convenience implementation of the default model
+objects and parsers used for writing pluggable support of alternate feature
+packaging schemes and update site access mechanisms. In general, most developers
+do not need to directly use the classes defined in this package. Instead,
+they can use the corresponding derived implementation classes contained
+in package <b>org.eclipse.update.core</b>.
+<p>Classes in this package would typically only be used directly when writing
+and alternate set of model objects for a feature and type implementation.
+<p>
+<b>Note:</b> This package has been deprecated and will be deleted in a future
+release. See bug 311590 for details.
+</p>
+</body>
+</html>
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/package.html b/update/org.eclipse.update.core/src/org/eclipse/update/core/package.html
new file mode 100644
index 0000000..693e7b1
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/package.html
@@ -0,0 +1,29 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="Author" content="IBM">
+ <meta name="GENERATOR" content="Mozilla/4.72 [en] (Windows NT 5.0; U) [Netscape]">
+ <title>Package-level Javadoc</title>
+</head>
+<body>
+Provides support for extending the base installation
+and update services.
+<h2>
+Package Specification</h2>
+This package specifies the API required for writing pluggable support of
+alternate feature packaging schemes and update site access mechanisms.
+For the most part, the classes and interfaces in this package implement
+a code pattern <tt>class Foo extends FooModel implements IFoo</tt>. The
+interface (<tt>IFoo</tt> in the pattern) defines the actual API. The convenience
+classes (<tt>Foo</tt> in the pattern) provide a reference implementation
+of the API based on a model (<tt>IFooModel</tt> in the pattern) contained
+in package <b>org.eclipse.update.core.model</b>. In general, developers
+should extend the convenience classes rather than completely reimplementing
+the specified interfaces.
+<p>
+<b>Note:</b> This package has been deprecated and will be deleted in a future
+release. See bug 311590 for details.
+</p>
+</body>
+</html>
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/BaseSiteLocalFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/BaseSiteLocalFactory.java
new file mode 100644
index 0000000..2ab5714
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/BaseSiteLocalFactory.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+import org.eclipse.update.core.model.*;
+import org.eclipse.update.internal.model.*;
+/**
+ *
+ */
+public class BaseSiteLocalFactory {
+ /*
+ *
+ */
+ public InstallConfigurationModel createInstallConfigurationModel() {
+ return new InstallConfiguration();
+ }
+ /*
+ *
+ */
+ public ConfigurationActivityModel createConfigurationActivityModel() {
+ return new ConfigurationActivity();
+ }
+ /*
+ *
+ */
+ public ConfiguredSiteModel createConfigurationSiteModel() {
+ return new ConfiguredSite();
+ }
+ /*
+ *
+ */
+ public ConfigurationPolicyModel createConfigurationPolicyModel() {
+ return new ConfigurationPolicy();
+ }
+ /**
+ *
+ */
+ public ConfiguredSiteModel createConfigurationSiteModel(SiteModel site, int policy) {
+ //create config site
+ ConfiguredSiteModel configSite = this.createConfigurationSiteModel();
+ configSite.setSiteModel(site);
+ ConfigurationPolicyModel policyModel = this.createConfigurationPolicyModel();
+ policyModel.setPolicy(policy);
+ configSite.setConfigurationPolicyModel(policyModel);
+ ((ConfigurationPolicy) policyModel).setConfiguredSiteModel(configSite);
+ return configSite;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ConfigurationActivity.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ConfigurationActivity.java
new file mode 100644
index 0000000..d6bbc84
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ConfigurationActivity.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.core;
+import org.eclipse.update.configuration.IActivity;
+import org.eclipse.update.configuration.IInstallConfiguration;
+import org.eclipse.update.internal.model.ConfigurationActivityModel;
+public class ConfigurationActivity
+ extends ConfigurationActivityModel
+ implements IActivity {
+
+ /**
+ * Default constructor
+ */
+ public ConfigurationActivity() {
+ }
+
+ /**
+ * Constructor with action
+ */
+ public ConfigurationActivity(int action) {
+ super();
+ setAction(action);
+ setStatus(STATUS_NOK);
+ }
+
+ /*
+ * @see IActivity#getInstallConfiguration()
+ */
+ public IInstallConfiguration getInstallConfiguration() {
+ return (IInstallConfiguration) getInstallConfigurationModel();
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof ConfigurationActivity))
+ return false;
+ if (this == other)
+ return true;
+
+ ConfigurationActivity activity = (ConfigurationActivity) other;
+ return getAction() == activity.getAction()
+ && getLabel().equals(activity.getLabel())
+ && getStatus() == activity.getStatus();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ConfigurationPolicy.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ConfigurationPolicy.java
new file mode 100644
index 0000000..5d7e482
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ConfigurationPolicy.java
@@ -0,0 +1,524 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+import java.io.*;
+import java.net.*;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.configurator.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.core.model.*;
+import org.eclipse.update.internal.model.*;
+
+/**
+ *
+ */
+public class ConfigurationPolicy extends ConfigurationPolicyModel {
+
+ /**
+ * Constructor for ConfigurationPolicyModel.
+ */
+ public ConfigurationPolicy() {
+ }
+
+ /**
+ * Copy Constructor for ConfigurationPolicyModel.
+ */
+ public ConfigurationPolicy(ConfigurationPolicy configPolicy) {
+ super();
+ setPolicy(configPolicy.getPolicy());
+ setConfiguredFeatureReferences(configPolicy.getConfiguredFeatures());
+ setUnconfiguredFeatureReferences(configPolicy.getUnconfiguredFeatures());
+ setConfiguredSiteModel(configPolicy.getConfiguredSiteModel());
+ }
+
+ /**
+ * @since 2.0
+ */
+ private boolean isUnconfigured(IFeatureReference featureReference) {
+
+ if (featureReference == null)
+ return false;
+
+ // returns true if the feature is part of the configured list
+ IFeatureReference[] refs = getUnconfiguredFeatures();
+ for (int i = 0; i < refs.length; i++) {
+ if (featureReference.equals(refs[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public boolean isConfigured(IFeatureReference featureReference) {
+
+ if (featureReference == null)
+ return false;
+
+ // returns true if the feature is part of the configured list
+ IFeatureReference[] refs = getConfiguredFeatures();
+ for (int i = 0; i < refs.length; i++) {
+ if (featureReference.equals(refs[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * adds the feature to the list of features if the policy is USER_INCLUDE
+ */
+ public void configure(IFeatureReference featureReference, boolean callInstallHandler, boolean createActivity) throws CoreException {
+
+ if (isConfigured(featureReference)) // already configured
+ return;
+
+ if (featureReference == null) {
+ UpdateCore.warn("The feature reference to configure is null"); //$NON-NLS-1$
+ return;
+ }
+
+ IFeature feature = null;
+ try {
+ feature = featureReference.getFeature(null);
+ } catch (CoreException e) {
+ if (!UpdateManagerUtils.isOptional(featureReference)) {
+ URL url = featureReference.getURL();
+ String urlString = (url != null) ? url.toExternalForm() : "<no feature reference url>"; //$NON-NLS-1$
+ UpdateCore.warn("Error retrieving feature:" + urlString, e); //$NON-NLS-1$
+ return;
+ }
+ }
+ if (feature == null) {
+ URL url = featureReference.getURL();
+ String urlString = (url != null) ? url.toExternalForm() : "<no feature reference url>"; //$NON-NLS-1$
+ UpdateCore.warn("The feature to unconfigure is null: feature reference is:" + urlString); //$NON-NLS-1$
+ }
+
+ // Setup optional install handler
+ InstallHandlerProxy handler = null;
+ if (callInstallHandler && feature.getInstallHandlerEntry() != null)
+ handler = new InstallHandlerProxy(IInstallHandler.HANDLER_ACTION_CONFIGURE, feature, feature.getInstallHandlerEntry(), null);
+ boolean success = false;
+ Throwable originalException = null;
+
+ // do the configure action
+ try {
+ if (handler != null)
+ handler.configureInitiated();
+
+ ConfigurationActivity activity = null;
+ if (createActivity) {
+ activity = new ConfigurationActivity(IActivity.ACTION_CONFIGURE);
+ activity.setLabel(feature.getVersionedIdentifier().toString());
+ activity.setDate(new Date());
+ }
+
+ addConfiguredFeatureReference((FeatureReferenceModel) featureReference);
+
+ // everything done ok
+ if (activity != null) {
+ InstallConfiguration installConfig = (InstallConfiguration) SiteManager.getLocalSite().getCurrentConfiguration();
+ activity.setStatus(IActivity.STATUS_OK);
+ installConfig.addActivity(activity);
+ }
+
+ if (handler != null)
+ handler.completeConfigure();
+
+ success = true;
+ } catch (Throwable t) {
+ originalException = t;
+ } finally {
+ Throwable newException = null;
+ try {
+ if (handler != null)
+ handler.configureCompleted(success);
+ } catch (Throwable t) {
+ newException = t;
+ }
+ if (originalException != null) // original exception wins
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallHandler_error, (new String[] { feature.getLabel() })), originalException);
+ if (newException != null)
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallHandler_error, (new String[] { feature.getLabel() })), newException);
+ }
+ }
+
+ /**
+ * check if the plugins to unconfigure are required by other configured feature and
+ * adds the feature to the list of unconfigured features
+ */
+ public boolean unconfigure(IFeatureReference featureReference, boolean callInstallHandler, boolean createActivity) throws CoreException {
+
+ if (isUnconfigured(featureReference)) {
+ UpdateCore.warn("Feature already unconfigured"); //$NON-NLS-1$
+ return true;
+ }
+
+ if (featureReference == null) {
+ UpdateCore.warn("The feature reference to unconfigure is null"); //$NON-NLS-1$
+ return false;
+ }
+
+ IFeature feature = null;
+ try {
+ feature = featureReference.getFeature(null);
+ } catch (CoreException e) {
+ if (!UpdateManagerUtils.isOptional(featureReference)) {
+ URL url = featureReference.getURL();
+ String urlString = (url != null) ? url.toExternalForm() : "<no feature reference url>"; //$NON-NLS-1$
+ UpdateCore.warn("Error retrieving feature:" + urlString, e); //$NON-NLS-1$
+ return false;
+ }
+ }
+
+ if (feature == null) {
+ URL url = featureReference.getURL();
+ String urlString = (url != null) ? url.toExternalForm() : "<no feature reference url>"; //$NON-NLS-1$
+ UpdateCore.warn("The feature to unconfigure is null: feature reference is:" + urlString); //$NON-NLS-1$
+ return false;
+ }
+
+ // Setup optional install handler
+ InstallHandlerProxy handler = null;
+ if (callInstallHandler && feature.getInstallHandlerEntry() != null) {
+ handler = new InstallHandlerProxy(IInstallHandler.HANDLER_ACTION_UNCONFIGURE, feature, feature.getInstallHandlerEntry(), null);
+ }
+
+ boolean success = false;
+ Throwable originalException = null;
+
+ // do the unconfigure action
+ try {
+
+ ConfigurationActivity activity = null;
+ if (createActivity) {
+ activity = new ConfigurationActivity(IActivity.ACTION_UNCONFIGURE);
+ activity.setLabel(feature.getVersionedIdentifier().toString());
+ activity.setDate(new Date());
+ }
+
+ InstallConfiguration installConfig = null;
+
+ // only ask for install config is activity created.
+ // prevents loops during reconciliation
+ if (activity != null)
+ installConfig = ((InstallConfiguration) SiteManager.getLocalSite().getCurrentConfiguration());
+
+ // Allow unconfigure if the feature is optional from all the parents
+ // or if the feature is mandatory and non of its parent are configured
+ // removed, not a core issue (so deep down)
+ //if (validateNoConfiguredParents(feature)) {
+ if (handler != null)
+ handler.unconfigureInitiated();
+ addUnconfiguredFeatureReference((FeatureReferenceModel) featureReference);
+ if (handler != null)
+ handler.completeUnconfigure();
+
+ // everything done ok
+ if (activity != null) {
+ activity.setStatus(IActivity.STATUS_OK);
+ installConfig.addActivity(activity);
+ }
+ success = true;
+ //} else {
+ // if (activity != null) {
+ // activity.setStatus(IActivity.STATUS_NOK);
+ // installConfig.addActivityModel((ConfigurationActivityModel) activity);
+ // }
+ //}
+ } catch (Throwable t) {
+ originalException = t;
+ } finally {
+ Throwable newException = null;
+ try {
+ if (handler != null)
+ handler.unconfigureCompleted(success);
+ } catch (Throwable t) {
+ newException = t;
+ }
+ if (originalException != null) // original exception wins
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallHandler_error, (new String[] { feature.getLabel() })), originalException);
+ if (newException != null)
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallHandler_error, (new String[] { feature.getLabel() })), newException);
+ }
+
+ if (!success) {
+ URL url = featureReference.getURL();
+ String urlString = (url != null) ? url.toExternalForm() : "<no feature reference url>"; //$NON-NLS-1$
+ UpdateCore.warn("Unable to unconfigure:" + urlString); //$NON-NLS-1$
+ }
+ return success;
+ }
+
+ /**
+ * Calculates the plugin list for the policy. For "INCLUDE" policy, this
+ * corresponds to the plugins for configured features. For "EXCLUDE"
+ * policy, this corresponds to the plugins for unconfigured features that
+ * are not referenced by any configured features.
+ */
+ public String[] getPluginPath(ISite site) throws CoreException {
+ // TODO we may need to exclude patched plugins here, but this should be good enough for now
+ if (getPolicy() == IPlatformConfiguration.ISitePolicy.MANAGED_ONLY)
+ return new String[0];
+
+ String[] pluginPaths;
+ // Note: Since 3.0M7 we leave patched features configured,
+ // and take this into account when computing configured plugins
+ // all unconfigured features. Note that patched features are still
+ // configured
+ IFeatureReference[] unconfiguredFeatures = getUnconfiguredFeatures();
+ // all configured features, including patches and patched features
+ IFeatureReference[] configuredFeatures = getConfiguredFeatures();
+ if (!isEnabled()) {
+ if (getPolicy() == IPlatformConfiguration.ISitePolicy.USER_INCLUDE) {
+ // disabled site, INCLUDE policy
+ pluginPaths = new String[0];
+ } else {
+ // disabled site, EXCLUDE policy
+ pluginPaths = getAllKnownPluginStrings(site,
+ configuredFeatures, unconfiguredFeatures);
+ }
+ } else {
+ // PatchedFeatures (may have no patches) with corresponding patches
+ PatchedFeature[] patchedFeatures = buildPatchedFeatures(configuredFeatures);
+ if (getPolicy() == IPlatformConfiguration.ISitePolicy.USER_INCLUDE) {
+ // enabled site, INCLUDE policy
+ pluginPaths = getConfiguredPluginStrings(site, patchedFeatures);
+ } else {
+ // enabled site, EXCLUDE policy - the usual scenario for local
+ // site.
+ // return all known MINUS configured plugins
+ pluginPaths = subtract(getAllKnownPluginStrings(site,
+ configuredFeatures, unconfiguredFeatures),
+ getConfiguredPluginStrings(site, patchedFeatures));
+ }
+ }
+ //TRACE
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) {
+ UpdateCore
+ .debug("GetPluginPath for: " //$NON-NLS-1$
+ + ((site == null) ? "<No site>" : site.getURL() //$NON-NLS-1$
+ .toString()));
+ for (int i = 0; i < pluginPaths.length; i++) {
+ UpdateCore.debug("To write:" + pluginPaths[i]); //$NON-NLS-1$
+ }
+ }
+ return pluginPaths;
+ }
+
+ /**
+ * Obtains PatchedFeatures - non patch features with corresponding patches if any
+ *
+ * @param features
+ * array of features to operate with
+ * @return Patches
+ */
+ private PatchedFeature[] buildPatchedFeatures(IFeatureReference[] features) {
+ // PatchedFeatures by VersionedIdentifier
+ Map map = new HashMap();
+ // Create a map of features (not patches)
+ for (int f = 0; f < features.length; f++) {
+ IFeatureReference featureRef = features[f];
+ try {
+ if(featureRef.isPatch()){
+ continue;
+ }
+ VersionedIdentifier vi = featureRef.getVersionedIdentifier();
+ map.put(vi, new PatchedFeature(features[f]));
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ }
+ }
+ // attach patches to features
+ for (int f = 0; f < features.length; f++) {
+ IFeatureReference patchCandidate = features[f];
+ try {
+ IFeature feature = patchCandidate.getFeature(null);
+ IImport[] imports = feature.getImports();
+ for (int i = 0; i < imports.length; i++) {
+ IImport oneImport = imports[i];
+ if (!oneImport.isPatch())
+ continue;
+ // it is a patch for
+ VersionedIdentifier patchedIdentifier =
+ oneImport.getVersionedIdentifier();
+ PatchedFeature pf=(PatchedFeature) map.get(patchedIdentifier);
+ if (pf!=null) {
+ pf.addPatch(patchCandidate);
+ } else {
+ // patched feature not enabled
+ }
+ }
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ }
+ }
+ Collection patchedFeatures=map.values();
+ return (PatchedFeature[])patchedFeatures.toArray(new PatchedFeature[patchedFeatures.size()]);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public IFeatureReference[] getConfiguredFeatures() {
+ FeatureReferenceModel[] result = getConfiguredFeaturesModel();
+ if (result.length == 0)
+ return new IFeatureReference[0];
+ else
+ return (IFeatureReference[]) result;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public IFeatureReference[] getUnconfiguredFeatures() {
+ FeatureReferenceModel[] result = getUnconfiguredFeaturesModel();
+ if (result.length == 0)
+ return new IFeatureReference[0];
+ else
+ return (IFeatureReference[]) result;
+ }
+
+ /**
+ * Gets the configuredSite.
+ * @return Returns a IConfiguredSite
+ */
+ public IConfiguredSite getConfiguredSite() {
+ return (IConfiguredSite) getConfiguredSiteModel();
+ }
+
+ /**
+ * removes a feature reference
+ */
+ public void removeFeatureReference(IFeatureReference featureRef) {
+ if (featureRef instanceof FeatureReferenceModel) {
+ removeFeatureReference((FeatureReferenceModel) featureRef);
+ }
+ }
+
+ /**
+ * @return an array of plugin path for the array of feature reference. For
+ * features that have patches, plugin path will
+ * point to plugin with the same ID provided by the patch if it
+ * exists. Each plugin path only appears once [bug 21750]
+ */
+ private String[] getConfiguredPluginStrings(ISite site, PatchedFeature[] features) throws CoreException {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION){
+ UpdateCore.warn("CONFIGURED PLUGINS"); //$NON-NLS-1$
+ }
+
+ // Use set to eliminate plugins with same ID and version.
+ // Different versions of plugins with same ID are allowed if coming from different features
+ Set featurePlugins = new HashSet();
+ for (int i = 0; i < features.length; i++) {
+ FeaturePlugin[] plugins = features[i].getPlugins();
+ featurePlugins.addAll(Arrays.asList(plugins));
+ }
+ Set pluginStrings = getPluginStrings(site, (FeaturePlugin[]) featurePlugins.toArray(new FeaturePlugin[featurePlugins.size()]));
+ return (String[]) pluginStrings.toArray(new String[pluginStrings.size()]);
+ }
+ /**
+ * @return an array of plugin path for every plugin in known features
+ */
+ private String[] getAllKnownPluginStrings(ISite site, IFeatureReference[] configured,IFeatureReference[] unconfigured) throws CoreException {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION){
+ UpdateCore.warn("ALL PLUGINS"); //$NON-NLS-1$
+ }
+ // Add features, patched features, or patches
+ IFeatureReference[] all=new IFeatureReference[configured.length+unconfigured.length];
+ System.arraycopy(configured, 0, all, 0, configured.length);
+ System.arraycopy(unconfigured, 0, all, configured.length, unconfigured.length);
+ //
+ Set patchedPlugins = new HashSet();
+ for (int i=0; i< all.length; i++) {
+ try {
+ IFeature feature = all[i].getFeature(null);
+ if (feature == null) {
+ UpdateCore.warn("Null Feature", new Exception()); //$NON-NLS-1$
+ continue;
+ }
+
+ IPluginEntry[] entries = feature.getPluginEntries();
+ // add every plugin to the map
+ for (int entr = 0; entr < entries.length; entr++) {
+ patchedPlugins.add(new FeaturePlugin(entries[entr], feature));
+ }
+
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ }
+ }
+ Set pluginStrings = getPluginStrings(site, (FeaturePlugin[])patchedPlugins.toArray(new FeaturePlugin[patchedPlugins.size()]));
+ return (String[]) pluginStrings.toArray(new String[pluginStrings.size()]);
+ }
+ /**
+ * @param site
+ * @param plugins[]
+ * @return valid string pointing to plugins in given features
+ * @throws CoreException
+ */
+ private Set getPluginStrings(ISite site, FeaturePlugin[] plugins) throws CoreException {
+ Set pluginStrings=new HashSet();
+ for (int i=0; i< plugins.length; i++) {
+ IPluginEntry entry = plugins[i].getEntry();
+ IFeature feature=plugins[i].getFeature();
+
+ // obtain the path of the plugin directories on the site
+ ContentReference[] featureContentReference = null;
+ try {
+ featureContentReference = feature.getFeatureContentProvider().getPluginEntryArchiveReferences(entry, null /*IProgressMonitor*/
+ );
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ }
+
+ // transform into a valid String
+ if (featureContentReference != null) {
+ for (int j = 0; j < featureContentReference.length; j++) {
+ URL url = site.getSiteContentProvider().getArchiveReference(featureContentReference[j].getIdentifier());
+ if (url != null) {
+ // make it relative to the site
+ String path = UpdateManagerUtils.getURLAsString(site.getURL(), url);
+ // add end "/"
+ if(!path.endsWith(".jar")) //$NON-NLS-1$
+ path += (path.endsWith(File.separator) || path.endsWith("/")) ? "" : "/"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ pluginStrings.add(path);
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION)
+ UpdateCore.warn("Add plugin: " + path + " to the list"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ }
+ }
+ return pluginStrings;
+ }
+
+ /**
+ * Obtains strings existing in the allStrings array, but not in the stringsToRemove
+ */
+ private String[] subtract(String[] allStrings, String[] stringsToRemove) {
+ HashSet resultList = new HashSet(Arrays.asList(allStrings));
+ resultList.removeAll(Arrays.asList(stringsToRemove));
+ return (String[])resultList.toArray(new String[resultList.size()]);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ConfiguredSite.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ConfiguredSite.java
new file mode 100644
index 0000000..3b59270
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ConfiguredSite.java
@@ -0,0 +1,1136 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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.update.internal.core;
+
+
+import org.eclipse.core.runtime.ListenerList;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.MissingResourceException;
+import java.util.PropertyResourceBundle;
+import java.util.Set;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.IActivity;
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.configuration.IConfiguredSiteChangedListener;
+import org.eclipse.update.configuration.IInstallConfiguration;
+import org.eclipse.update.configuration.IProblemHandler;
+import org.eclipse.update.configurator.ConfiguratorUtils;
+import org.eclipse.update.configurator.IPlatformConfiguration;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IFeatureReference;
+import org.eclipse.update.core.IIncludedFeatureReference;
+import org.eclipse.update.core.IPluginEntry;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.ISiteFeatureReference;
+import org.eclipse.update.core.IVerificationListener;
+import org.eclipse.update.core.SiteManager;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.core.VersionedIdentifier;
+import org.eclipse.update.core.model.InstallAbortedException;
+import org.eclipse.update.internal.model.ConfiguredSiteModel;
+import org.eclipse.update.internal.operations.UpdateUtils;
+
+/**
+ * A Configured site manages the Configured and unconfigured features of a Site
+ */
+public class ConfiguredSite extends ConfiguredSiteModel implements IConfiguredSite {
+
+ private static final String PRODUCT_SITE_MARKER = ".eclipseproduct"; //$NON-NLS-1$
+ private static final String EXTENSION_SITE_MARKER = ".eclipseextension"; //$NON-NLS-1$
+
+ // listeners
+ private ListenerList listeners = new ListenerList(ListenerList.IDENTITY);
+
+ // verification status
+ private IStatus verifyStatus;
+
+ // transient: true if the site was just created so we can remove it
+ private transient boolean justCreated = false;
+
+ /*
+ * Default Constructor
+ */
+ public ConfiguredSite() {
+ }
+
+ /*
+ * Copy Constructor
+ * As of now, configSite can only be of type ConfiguredSite
+ */
+ public ConfiguredSite(IConfiguredSite configSite) {
+ ConfiguredSite cSite = (ConfiguredSite) configSite;
+ setSiteModel(cSite.getSiteModel());
+ setConfigurationPolicyModel(new ConfigurationPolicy(cSite.getConfigurationPolicy()));
+ setUpdatable(cSite.isUpdatable());
+ setEnabled(cSite.isEnabled());
+ setPreviousPluginPath(cSite.getPreviousPluginPath());
+ setPlatformURLString(cSite.getPlatformURLString());
+ }
+
+ /*
+ * Adds a listener
+ */
+ public void addConfiguredSiteChangedListener(IConfiguredSiteChangedListener listener) {
+ listeners.add(listener);
+ }
+
+ /*
+ * Removes a listener
+ */
+ public void removeConfiguredSiteChangedListener(IConfiguredSiteChangedListener listener) {
+ listeners.remove(listener);
+ }
+
+ /*
+ * @see IConfiguredSite#install(IFeature,IVerificationListener, IProgressMonitor)
+ */
+ public IFeatureReference install(IFeature feature, IVerificationListener verificationListener, IProgressMonitor monitor) throws InstallAbortedException, CoreException {
+ return install(feature, null, verificationListener, monitor);
+ }
+
+ /*
+ * @see IConfiguredSite#install(IFeature, IFeatureReference, IVerificationListener, IProgressMonitor)
+ */
+ public IFeatureReference install(IFeature feature, IFeatureReference[] optionalFeatures, IVerificationListener verificationListener, IProgressMonitor monitor) throws InstallAbortedException, CoreException {
+
+ // change the status if justCreated
+ if (justCreated) justCreated=false;
+
+ // ConfigSite is read only
+ if (!isUpdatable()) {
+ String errorMessage = NLS.bind(Messages.ConfiguredSite_NonInstallableSite, (new String[] { getSite().getURL().toExternalForm() }));
+ IStatus status = verifyUpdatableStatus();
+ if (status != null)
+ errorMessage += " " + status.getMessage(); //$NON-NLS-1$
+ throw Utilities.newCoreException(errorMessage, null);
+ }
+
+ // feature is null
+ if (feature == null) {
+ String errorMessage = Messages.ConfiguredSite_NullFeatureToInstall;
+ throw Utilities.newCoreException(errorMessage, null);
+ }
+
+ // feature reference to return
+ IFeatureReference installedFeatureRef;
+ IFeature installedFeature = null;
+
+ // create the Activity (INSTALL)
+ ConfigurationActivity activity = new ConfigurationActivity(IActivity.ACTION_FEATURE_INSTALL);
+ activity.setLabel(feature.getVersionedIdentifier().toString());
+ activity.setDate(new Date());
+
+ try {
+ installedFeatureRef = getSite().install(feature, optionalFeatures, verificationListener, monitor);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL) {
+ UpdateCore.debug("Sucessfully installed: " + installedFeatureRef.getURL().toExternalForm()); //$NON-NLS-1$
+ }
+
+ if (installedFeatureRef != null) {
+ try {
+ installedFeature = installedFeatureRef.getFeature(null);
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ }
+ }
+
+ // everything done ok
+ activity.setStatus(IActivity.STATUS_OK);
+
+ // notify listeners
+ Object[] siteListeners = listeners.getListeners();
+ for (int i = 0; i < siteListeners.length; i++) {
+ if (installedFeature != null) {
+ IConfiguredSiteChangedListener listener = ((IConfiguredSiteChangedListener) siteListeners[i]);
+ listener.featureInstalled(installedFeature);
+ }
+ }
+ } catch (CoreException e) {
+ // not ok, set Activity status
+ activity.setStatus(IActivity.STATUS_NOK);
+ throw e;
+ } finally {
+ IInstallConfiguration current = SiteManager.getLocalSite().getCurrentConfiguration();
+ ((InstallConfiguration) current).addActivity(activity);
+ }
+ // call the configure task
+ if (installedFeature != null)
+ configure(installedFeature, optionalFeatures, true);
+ /*callInstallHandler*/
+
+ return installedFeatureRef;
+ }
+
+ /*
+ * @see IConfiguredSite#remove(IFeature, IProgressMonitor)
+ */
+ public void remove(IFeature feature, IProgressMonitor monitor) throws CoreException {
+
+ // ConfigSite is read only
+ if (!isUpdatable()) {
+ String errorMessage = NLS.bind(Messages.ConfiguredSite_NonUninstallableSite, (new String[] { getSite().getURL().toExternalForm() }));
+ throw Utilities.newCoreException(errorMessage, null);
+ }
+
+ // create the Activity
+ ConfigurationActivity activity = new ConfigurationActivity(IActivity.ACTION_FEATURE_REMOVE);
+ activity.setLabel(feature.getVersionedIdentifier().toString());
+ activity.setDate(new Date());
+
+ try {
+ IFeatureReference referenceToRemove = null;
+ ISiteFeatureReference[] featureRef = getSite().getFeatureReferences();
+ ISiteFeatureReference ref = getSite().getFeatureReference(feature);
+ for (int i = 0; i < featureRef.length; i++) {
+ if (featureRef[i].equals(ref)) {
+ referenceToRemove = featureRef[i];
+ break;
+ }
+ }
+
+ // we found a feature reference on the site matching the feature
+ if (referenceToRemove != null) {
+ // Check if feature is unconfigured before we remove it
+ // our UI will check.
+ // For non-UI application, throw error is feature is configured
+ if (getConfigurationPolicy().isConfigured(referenceToRemove)) {
+ IFeature featureToRemove = referenceToRemove.getFeature(null);
+ String featureLabel = (featureToRemove == null) ? null : featureToRemove.getLabel();
+ throw Utilities.newCoreException(NLS.bind(Messages.ConfiguredSite_UnableToRemoveConfiguredFeature, (new String[] { featureLabel })), null);
+ }
+ } else {
+ throw Utilities.newCoreException(NLS.bind(Messages.ConfiguredSite_UnableToFindFeature, (new String[] { feature.getURL().toString() })),
+ null);
+ }
+
+ // remove the feature
+ getSite().remove(feature, monitor);
+ getConfigurationPolicy().removeFeatureReference(referenceToRemove);
+ // everything done ok
+ activity.setStatus(IActivity.STATUS_OK);
+ // notify listeners
+ Object[] siteListeners = listeners.getListeners();
+ for (int i = 0; i < siteListeners.length; i++) {
+ ((IConfiguredSiteChangedListener) siteListeners[i]).featureRemoved(feature);
+ }
+ } catch (CoreException e) {
+ activity.setStatus(IActivity.STATUS_NOK);
+ throw e;
+ } finally {
+ IInstallConfiguration current = SiteManager.getLocalSite().getCurrentConfiguration();
+ ((InstallConfiguration) current).addActivity(activity);
+ }
+ }
+
+ /*
+ * @see IConfiguredSite#configure(IFeature)
+ */
+ public void configure(IFeature feature) throws CoreException {
+ configure(feature, null, true /*callInstallHandler*/
+ );
+ }
+
+ /*
+ *
+ */
+ private void configure(IFeature feature, IFeatureReference[] optionalFeatures, boolean callInstallHandler) throws CoreException {
+
+ if (feature == null) {
+ UpdateCore.warn("Attempting to configure a null feature in site:" + getSite().getURL().toExternalForm()); //$NON-NLS-1$
+ return;
+ }
+
+ ConfigurationPolicy configPolicy = getConfigurationPolicy();
+ if (configPolicy == null)
+ return;
+
+ // bottom up approach, same configuredSite
+ IIncludedFeatureReference[] childrenRef = feature.getIncludedFeatureReferences();
+ if (optionalFeatures != null) {
+ childrenRef = childrenToConfigure(childrenRef, optionalFeatures);
+ }
+
+ for (int i = 0; i < childrenRef.length; i++) {
+ try {
+ IFeature child = childrenRef[i].getFeature(null);
+ configure(child, optionalFeatures, callInstallHandler);
+ } catch (CoreException e) {
+ // if not an optional feature, throw exception
+ if (!childrenRef[i].isOptional()) {
+ UpdateCore.warn("Unable to configure child feature: " + childrenRef[i] + " " + e); //$NON-NLS-1$ //$NON-NLS-2$
+ throw e;
+ }
+ }
+ }
+
+ // configure root feature
+ IFeatureReference featureReference = getSite().getFeatureReference(feature);
+ configPolicy.configure(featureReference, callInstallHandler, true);
+
+ // notify listeners
+ Object[] siteListeners = listeners.getListeners();
+ for (int i = 0; i < siteListeners.length; i++) {
+ ((IConfiguredSiteChangedListener) siteListeners[i]).featureConfigured(feature);
+ }
+ }
+
+ /*
+ * Return the optional children to configure
+ *
+ * @param children all the nested features
+ * @param optionalfeatures optional features to install
+ * @return IFeatureReference[]
+ */
+ private IIncludedFeatureReference[] childrenToConfigure(IIncludedFeatureReference[] children, IFeatureReference[] optionalfeatures) {
+
+ List childrenToInstall = new ArrayList();
+ for (int i = 0; i < children.length; i++) {
+ IIncludedFeatureReference optionalFeatureToConfigure = children[i];
+ if (!optionalFeatureToConfigure.isOptional()) {
+ childrenToInstall.add(optionalFeatureToConfigure);
+ } else {
+ for (int j = 0; j < optionalfeatures.length; j++) {
+ // must compare feature as optionalFeatures are from the install site
+ // where children are on the local site
+ try {
+ IFeature installedChildren = optionalfeatures[j].getFeature(null);
+ if (installedChildren.equals(optionalFeatureToConfigure.getFeature(null))) {
+ childrenToInstall.add(optionalFeatureToConfigure);
+ break;
+ }
+ } catch (CoreException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ IIncludedFeatureReference[] result = new IIncludedFeatureReference[childrenToInstall.size()];
+ if (childrenToInstall.size() > 0) {
+ childrenToInstall.toArray(result);
+ }
+
+ return result;
+ }
+
+ /*
+ * @see IConfiguredSite#unconfigure(IFeature)
+ */
+ public boolean unconfigure(IFeature feature) throws CoreException {
+ // the first call sould disable without checking for enable parent
+ return unconfigure(feature, true, false);
+ }
+
+ private boolean unconfigure(IFeature feature, boolean includePatches, boolean verifyEnableParent) throws CoreException {
+ IFeatureReference featureReference = getSite().getFeatureReference(feature);
+
+ if (featureReference == null) {
+ UpdateCore.warn("Unable to retrieve Feature Reference for feature" + feature); //$NON-NLS-1$
+ return false;
+ }
+
+ ConfigurationPolicy configPolicy = getConfigurationPolicy();
+ if (configPolicy == null)
+ return false;
+
+ // verify no enable parent
+ if (verifyEnableParent && !validateNoConfiguredParents(feature)) {
+ UpdateCore.warn("The feature " + feature.getVersionedIdentifier() + " to disable is needed by another enable feature"); //$NON-NLS-1$ //$NON-NLS-2$
+ return false;
+ }
+
+ boolean sucessfullyUnconfigured = false;
+ try {
+ sucessfullyUnconfigured = configPolicy.unconfigure(featureReference, true, true);
+ } catch (CoreException e) {
+ URL url = featureReference.getURL();
+ String urlString = (url != null) ? url.toExternalForm() : "<no feature reference url>"; //$NON-NLS-1$
+ UpdateCore.warn("Unable to unconfigure" + urlString, e); //$NON-NLS-1$
+ throw e;
+ }
+ if (sucessfullyUnconfigured) {
+ // 2.0.2: unconfigure patches that reference this feature.
+ // A patch is a feature that contains an import
+ // statement with patch="true" and an id/version
+ // that matches an already installed and configured
+ // feature. When patched feature is unconfigured,
+ // all the patches that reference it must be
+ // unconfigured as well
+ // (in contrast, patched features can be
+ // configured without the patches).
+ if (includePatches)
+ unconfigurePatches(feature);
+
+ // top down approach, same configuredSite
+ IIncludedFeatureReference[] childrenRef = feature.getIncludedFeatureReferences();
+ for (int i = 0; i < childrenRef.length; i++) {
+ try {
+ IFeature child = childrenRef[i].getFeature(null); // disable the exact feature
+ unconfigure(child, includePatches, true); // check for parent as we should be the only parent.
+ } catch (CoreException e) {
+ // skip any bad children
+ UpdateCore.warn("Unable to unconfigure child feature: " + childrenRef[i] + " " + e); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ // notify listeners
+ Object[] siteListeners = listeners.getListeners();
+ for (int i = 0; i < siteListeners.length; i++) {
+ IConfiguredSiteChangedListener listener = ((IConfiguredSiteChangedListener) siteListeners[i]);
+ listener.featureUnconfigured(feature);
+ }
+
+ return true;
+ } else {
+ URL url = featureReference.getURL();
+ String urlString = (url != null) ? url.toExternalForm() : "<no feature reference url>"; //$NON-NLS-1$
+ UpdateCore.warn("Unable to unconfigure:" + urlString); //$NON-NLS-1$
+ return false;
+ }
+ }
+
+ /*
+ * Look for features that have an import reference
+ * that points to this feature and where patch=true.
+ * Unconfigure all the matching patches, but
+ * do not do the same lookup for them
+ * because patches cannot have patches themselves.
+ */
+
+ private void unconfigurePatches(IFeature feature) {
+ IFeatureReference[] frefs = getConfiguredFeatures();
+ for (int i = 0; i < frefs.length; i++) {
+ IFeatureReference fref = frefs[i];
+ try {
+ IFeature candidate = fref.getFeature(null);
+ if (candidate.equals(feature))
+ continue;
+
+ if (UpdateUtils.isPatch(feature, candidate))
+ unconfigure(candidate, false, false);
+ } catch (CoreException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /*
+ * @see IConfiguredSite#getConfiguredFeatures()
+ */
+ public IFeatureReference[] getConfiguredFeatures() {
+ if (isEnabled())
+ return getRawConfiguredFeatures();
+ else
+ return new ISiteFeatureReference[0];
+ }
+
+ /*
+ * @see IConfiguredSite#getConfiguredFeatures()
+ */
+ private IFeatureReference[] getRawConfiguredFeatures() {
+ ConfigurationPolicy configPolicy = getConfigurationPolicy();
+ if (configPolicy == null)
+ return new ISiteFeatureReference[0];
+
+ return configPolicy.getConfiguredFeatures();
+ }
+
+ /*
+ * adds configured and unconfigured feature references
+ */
+ public IFeatureReference[] getFeatureReferences() {
+
+ ConfigurationPolicy configPolicy = getConfigurationPolicy();
+ if (configPolicy == null)
+ return new ISiteFeatureReference[0];
+
+ IFeatureReference[] configuredFeatures = getConfiguredFeatures();
+ int confLen = configuredFeatures.length;
+ IFeatureReference[] unconfiguredFeatures = configPolicy.getUnconfiguredFeatures();
+ int unconfLen = unconfiguredFeatures.length;
+
+ IFeatureReference[] result = new IFeatureReference[confLen + unconfLen];
+ if (confLen > 0) {
+ System.arraycopy(configuredFeatures, 0, result, 0, confLen);
+ }
+ if (unconfLen > 0) {
+ System.arraycopy(unconfiguredFeatures, 0, result, confLen, unconfLen);
+ }
+
+ return result;
+ }
+
+ /*
+ * Configure and unconfigure appropriate feature to
+ * become 'like' currentConfiguration which is the configuration
+ * the user wants to revert to.
+ *
+ * All features from currentConfiguration should be configured
+ */
+ public void revertTo(IConfiguredSite oldConfiguration, IProgressMonitor monitor, IProblemHandler handler) throws CoreException, InterruptedException {
+
+ ConfiguredSite oldConfiguredSite = (ConfiguredSite) oldConfiguration;
+
+ // retrieve the feature that were configured
+ IFeatureReference[] configuredFeatures = oldConfiguredSite.validConfiguredFeatures(handler);
+
+ for (int i = 0; i < configuredFeatures.length; i++) {
+ getConfigurationPolicy().configure(configuredFeatures[i], true, true);
+ }
+
+ // calculate all the features we have to unconfigure from the current state to this state
+ // in the history.
+ List featureToUnconfigure = oldConfiguredSite.calculateUnconfiguredFeatures(configuredFeatures);
+
+ // for each unconfigured feature check if it still exists
+ // if so add as unconfigured
+ Iterator iter = featureToUnconfigure.iterator();
+ while (iter.hasNext()) {
+ IFeatureReference element = (IFeatureReference) iter.next();
+ try {
+ // do not log activity
+ getConfigurationPolicy().unconfigure(element, true, true);
+ } catch (CoreException e) {
+ // log no feature to unconfigure
+ String url = element.getURL().toString();
+ ISite site = element.getSite();
+ String siteString = (site != null) ? site.getURL().toExternalForm() : Messages.ConfiguredSite_NoSite;
+ UpdateCore.warn(NLS.bind(Messages.ConfiguredSite_CannotFindFeatureToUnconfigure, (new String[] { url, siteString })), e);
+ }
+ }
+ //} // end USER_EXCLUDE
+ }
+
+ /*
+ * We have to keep our configured feature
+ * check if they are all valid
+ * Return the valid configured features
+ */
+ private IFeatureReference[] validConfiguredFeatures(IProblemHandler handler) throws InterruptedException {
+
+ IFeatureReference[] configuredFeatures = getConfiguredFeatures();
+ if (configuredFeatures != null) {
+ for (int i = 0; i < configuredFeatures.length; i++) {
+ IFeature feature = null;
+
+ // attempt to access the feature
+ try {
+ feature = configuredFeatures[i].getFeature(null);
+ } catch (CoreException e) {
+ // notify we cannot find the feature
+ UpdateCore.warn(null, e);
+ String featureString = configuredFeatures[i].getURL().toExternalForm();
+ if (!handler.reportProblem(NLS.bind(Messages.ConfiguredSite_CannotFindFeatureToConfigure, (new String[] { featureString })))) {
+ throw new InterruptedException();
+ }
+ }
+
+ // verify all the plugins still exist
+ if (feature != null) {
+ // get plugin identifier
+ List sitePluginIdentifiers = new ArrayList();
+ ISite site = feature.getSite();
+ IPluginEntry[] sitePluginEntries = null;
+
+ if (site != null) {
+ sitePluginEntries = site.getPluginEntries();
+ for (int index = 0; index < sitePluginEntries.length; index++) {
+ IPluginEntry entry = sitePluginEntries[index];
+ sitePluginIdentifiers.add(entry.getVersionedIdentifier());
+ }
+ }
+
+ if (sitePluginEntries.length > 0) {
+ IPluginEntry[] featurePluginEntries = feature.getPluginEntries();
+ for (int index = 0; index < featurePluginEntries.length; index++) {
+ IPluginEntry currentFeaturePluginEntry = featurePluginEntries[index];
+ if (!contains(currentFeaturePluginEntry.getVersionedIdentifier(), sitePluginIdentifiers)) {
+ // the plugin defined by the feature
+ // doesn't seem to exist on the site
+ String msg = "Error verifying existence of plugin:" + currentFeaturePluginEntry.getVersionedIdentifier().toString(); //$NON-NLS-1$
+ UpdateCore.log(msg, new Exception());
+
+ String siteString = (site != null) ? site.getURL().toExternalForm() : Messages.ConfiguredSite_NoSite;
+ String errorLabel = NLS.bind(Messages.ConfiguredSite_CannotFindPluginEntry, (new String[] { currentFeaturePluginEntry.getVersionedIdentifier().toString(), siteString }));
+ if (handler == null) {
+ throw new InterruptedException(errorLabel);
+ }
+ if (!handler.reportProblem(errorLabel)) {
+ throw new InterruptedException();
+ }
+ } // end if not found in site
+ } // end for
+ }
+ }
+ } // end for configured feature
+ }
+ return configuredFeatures;
+ }
+
+ /*
+ * We are in the process of calculating the delta between what was configured in the current
+ * configuration that is not configured now
+ *
+ * we have to figure out what feature have been unconfigured for the whole
+ * history between current and us...
+ *
+ * is it as simple as get all configured, and unconfigured,
+ * the do the delta with what should be configured
+ *
+ */
+ private List calculateUnconfiguredFeatures(IFeatureReference[] configuredFeatures) throws CoreException {
+
+ Set featureToUnconfigureSet = new HashSet();
+
+ // loop for all history
+ // try to see if the configured site existed
+ // if it does, get the unconfigured features
+ // and the configured one
+ IInstallConfiguration[] history = SiteManager.getLocalSite().getConfigurationHistory();
+
+ for (int i = 0; i < history.length; i++) {
+ IInstallConfiguration element = history[i];
+ IConfiguredSite[] configSites = element.getConfiguredSites();
+ for (int j = 0; j < configSites.length; j++) {
+ ConfiguredSite configSite = (ConfiguredSite) configSites[j];
+ if (configSite.getSite().equals(getSite())) {
+ featureToUnconfigureSet.addAll(Arrays.asList(configSite.getConfigurationPolicy().getUnconfiguredFeatures()));
+ featureToUnconfigureSet.addAll(Arrays.asList(configSite.getConfigurationPolicy().getConfiguredFeatures()));
+ }
+ }
+ }
+
+ // remove the unconfigured feature we found that are now to be configured
+ // (they may have been unconfigured in the past, but the revert makes them configured)
+ List featureToUnconfigureList = remove(configuredFeatures, featureToUnconfigureSet);
+
+ return featureToUnconfigureList;
+ }
+
+ /*
+ * Utilities: Remove an array of feature references
+ * from a list
+ */
+ private List remove(IFeatureReference[] featureRefs, Set set) {
+ List result = new ArrayList();
+
+ if (set == null)
+ return result;
+
+ // if an element of the list is NOT found in the array,
+ // add it to the result list
+ Iterator iter = set.iterator();
+ while (iter.hasNext()) {
+ IFeatureReference element = (IFeatureReference) iter.next();
+ boolean found = false;
+ for (int i = 0; i < featureRefs.length; i++) {
+ if (element.equals(featureRefs[i])) {
+ found = true;
+ }
+ }
+
+ if (!found)
+ result.add(element);
+ }
+ return result;
+ }
+
+ /*
+ * I have issues when running list.contain(versionedIdentifier)
+ * The code runs the Object.equals instead of the VersionedIdentifier.equals
+ */
+ private boolean contains(VersionedIdentifier id, List list) {
+ boolean found = false;
+ if (list != null && !list.isEmpty()) {
+ Iterator iter = list.iterator();
+ while (iter.hasNext() && !found) {
+ VersionedIdentifier element = (VersionedIdentifier) iter.next();
+ if (element.equals(id)) {
+ found = true;
+ }
+ }
+ }
+ return found;
+ }
+
+ /*
+ *
+ */
+ public ConfigurationPolicy getConfigurationPolicy() {
+ return (ConfigurationPolicy) getConfigurationPolicyModel();
+ }
+
+ /*
+ *
+ */
+ public ISite getSite() {
+ return (ISite) getSiteModel();
+ }
+
+ /*
+ *
+ */
+ public IInstallConfiguration getInstallConfiguration() {
+ return (IInstallConfiguration) getInstallConfigurationModel();
+ }
+
+ /*
+ *
+ */
+ public IStatus getBrokenStatus(IFeature feature) {
+
+ IStatus featureStatus = createStatus(IStatus.OK, IFeature.STATUS_HAPPY, "", null); //$NON-NLS-1$
+
+ // check the Plugins of all the features
+ // every plugin of the feature must be on the site
+ IPluginEntry[] siteEntries = getSite().getPluginEntries();
+ IPluginEntry[] featuresEntries = feature.getPluginEntries();
+ IPluginEntry[] result = UpdateManagerUtils.diff(featuresEntries, siteEntries);
+ if (result != null && (result.length != 0)) {
+ String msg = Messages.SiteLocal_FeatureUnHappy;
+ MultiStatus multi = new MultiStatus(featureStatus.getPlugin(), IFeature.STATUS_UNHAPPY, msg, null);
+
+ for (int k = 0; k < result.length; k++) {
+ VersionedIdentifier id = result[k].getVersionedIdentifier();
+ Object[] values = new String[] { "", "" }; //$NON-NLS-1$ //$NON-NLS-2$
+ if (id != null) {
+ values = new Object[] { id.getIdentifier(), id.getVersion()};
+ }
+ String msg1 = NLS.bind(Messages.ConfiguredSite_MissingPluginsBrokenFeature, values);
+ UpdateCore.warn(msg1);
+ IStatus status = createStatus(IStatus.ERROR, IFeature.STATUS_UNHAPPY, msg1, null);
+ multi.add(status);
+ }
+ return multi;
+ }
+
+ // check os, arch, and ws
+
+ String msg = Messages.SiteLocal_FeatureHappy;
+ return createStatus(IStatus.OK, IFeature.STATUS_HAPPY, msg, null);
+ }
+
+ /*
+ *
+ */
+ public boolean isConfigured(IFeature feature) {
+ if (!isEnabled())
+ return false;
+
+ if (getConfigurationPolicy() == null)
+ return false;
+ IFeatureReference featureReference = getSite().getFeatureReference(feature);
+ if (featureReference == null) {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_WARNINGS)
+ UpdateCore.warn("Unable to retrieve featureReference for feature:" + feature); //$NON-NLS-1$
+ return false;
+ }
+ return getConfigurationPolicy().isConfigured(featureReference);
+ }
+
+ /**
+ * @see Object#toString()
+ */
+ public String toString() {
+ if (getSite() == null)
+ return "No Site"; //$NON-NLS-1$
+ if (getSite().getURL() == null)
+ return "No URL"; //$NON-NLS-1$
+ return getSite().getURL().toExternalForm();
+ }
+
+ /**
+ * @see IConfiguredSite#verifyUpdatableStatus()
+ */
+ public IStatus verifyUpdatableStatus() {
+
+ if (verifyStatus != null)
+ return verifyStatus;
+
+ URL siteURL = getSite().getURL();
+ if (siteURL == null) {
+ verifyStatus = createStatus(IStatus.ERROR, Messages.ConfiguredSite_SiteURLNull, null);
+ return verifyStatus;
+ }
+
+ if (!"file".equalsIgnoreCase(siteURL.getProtocol())) { //$NON-NLS-1$
+ verifyStatus = createStatus(IStatus.ERROR, Messages.ConfiguredSite_NonLocalSite, null);
+ return verifyStatus;
+ }
+
+ String siteLocation = siteURL.getFile();
+ File file = new File(siteLocation);
+
+ // get the product name of the private marker
+ // if there is no private marker, check if the site is contained in another site
+ // if there is a marker and this is a different product, return false
+ // otherwise don't check if we are contained in another site
+ String productName = getProductName(file);
+ if (productName != null) {
+ if (!productName.equals(getProductIdentifier("id", getProductFile()))) { //$NON-NLS-1$
+ verifyStatus = createStatus(IStatus.ERROR, NLS.bind(Messages.ConfiguredSite_NotSameProductId, (new String[] { productName })), null);
+ return verifyStatus;
+ }
+ } else {
+ File container = getSiteContaining(file);
+ // allow the install location to pass even though it looks like this
+ // site is contained in another site
+ if (container != null && !siteLocation.equals(Platform.getInstallLocation().getURL().getFile())) {
+ verifyStatus = createStatus(IStatus.ERROR, NLS.bind(Messages.ConfiguredSite_ContainedInAnotherSite, (new String[] { container.getAbsolutePath() })), null);
+ return verifyStatus;
+ }
+ }
+
+ if (!canWrite(file)) {
+ verifyStatus = createStatus(IStatus.ERROR, Messages.ConfiguredSite_ReadOnlySite, null);
+ return verifyStatus;
+ }
+
+ verifyStatus = createStatus(IStatus.OK, "", null); //$NON-NLS-1$
+ setUpdatable(true);
+ return verifyStatus;
+ }
+
+ /*
+ * Verify we can write on the file system
+ */
+ public static boolean canWrite(File file) {
+ if (file.canWrite() == false)
+ return false;
+
+ if (!file.isDirectory())
+ return false;
+
+ File fileTest = null;
+ try {
+ // we use the .dll suffix to properly test on Vista virtual directories
+ // on Vista you are not allowed to write executable files on virtual directories like "Program Files"
+ fileTest = File.createTempFile("writtableArea", ".dll", file); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (IOException e) {
+ //If an exception occurred while trying to create the file, it means that it is not writable
+ return false;
+ } finally {
+ if (fileTest != null)
+ fileTest.delete();
+ }
+ return true;
+ }
+
+ /*
+ * Check if the directory contains a marker
+ * if not ask all directory children to check
+ * if one validates the condition, returns the marker
+ */
+ private static File getSiteContaining(File file) {
+
+ if (file == null)
+ return null;
+
+ UpdateCore.warn("IsContained: Checking for markers at:" + file); //$NON-NLS-1$
+ if (file.exists() && file.isDirectory()) {
+ File productFile = new File(file, PRODUCT_SITE_MARKER);
+ File extensionFile = new File(file, EXTENSION_SITE_MARKER);
+ if (productFile.exists() || extensionFile.exists())
+ return file;
+// // do not check if a marker exists in the current but start from the parent
+// // the current is analyze by getProductname()
+// if (file.getParentFile() != null) {
+// File privateFile = new File(file.getParentFile(), PRIVATE_SITE_MARKER);
+// if (privateFile.exists())
+// return file.getParentFile();
+// }
+ }
+ return getSiteContaining(file.getParentFile());
+ }
+
+ /*
+ * Returns the name of the product if the identifier of the private Site markup is not
+ * the same as the identifier of the product the workbench was started with.
+ * If the product is the same, return null.
+ */
+ private static String getProductName(File file) {
+
+ if (file == null)
+ return null;
+
+ File markerFile = new File(file, EXTENSION_SITE_MARKER );
+ if (!markerFile.exists()) {
+ return null;
+ }
+
+ File productFile = getProductFile();
+ String productId = null;
+ String privateId = null;
+ if (productFile != null) {
+ productId = getProductIdentifier("id", productFile); //$NON-NLS-1$
+ privateId = getProductIdentifier("id", markerFile); //$NON-NLS-1$
+ if (productId == null) {
+ UpdateCore.warn("Product ID is null at:" + productFile); //$NON-NLS-1$
+ return null;
+ }
+ if (!productId.equalsIgnoreCase(privateId)) {
+ UpdateCore.warn("Product id at" + productFile + " Different than:" + markerFile); //$NON-NLS-1$ //$NON-NLS-2$
+ String name = getProductIdentifier("name", markerFile); //$NON-NLS-1$
+ String version = getProductIdentifier("version", markerFile); //$NON-NLS-1$
+ String markerID = (name == null) ? version : name + ":" + version; //$NON-NLS-1$
+ if (markerID == null)
+ markerID = ""; //$NON-NLS-1$
+ return markerID;
+ } else {
+ return privateId;
+ }
+ } else {
+ UpdateCore.warn("Product Marker doesn't exist:" + productFile); //$NON-NLS-1$
+ }
+
+ return null;
+ }
+
+ /*
+ * Returns the identifier of the product from the property file
+ */
+ private static String getProductIdentifier(String identifier, File propertyFile) {
+ String result = null;
+ if (identifier == null)
+ return result;
+ InputStream in = null;
+ try {
+ in = new FileInputStream(propertyFile);
+ PropertyResourceBundle bundle = new PropertyResourceBundle(in);
+ result = bundle.getString(identifier);
+ } catch (IOException e) {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL)
+ UpdateCore.debug("Exception reading property file:" + propertyFile); //$NON-NLS-1$
+ } catch (MissingResourceException e) {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL)
+ UpdateCore.debug("Exception reading '" + identifier + "' from property file:" + propertyFile); //$NON-NLS-1$ //$NON-NLS-2$
+ } finally {
+ if (in != null)
+ try {
+ in.close();
+ } catch (IOException e1) {
+ }
+ }
+ return result;
+ }
+
+ /*
+ * Returns the identifier of the product from the property file
+ */
+ private static File getProductFile() {
+
+ String productInstallDirectory = ConfiguratorUtils.getInstallURL().getFile();
+ if (productInstallDirectory != null) {
+ File productFile = new File(productInstallDirectory, PRODUCT_SITE_MARKER);
+ if (productFile.exists()) {
+ return productFile;
+ } else {
+ UpdateCore.warn("Product marker doesn't exist:" + productFile); //$NON-NLS-1$
+ }
+ } else {
+ UpdateCore.warn("Cannot retrieve install URL from BootLoader"); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /*
+ *
+ */
+ /*package*/
+ boolean createPrivateSiteMarker() {
+ URL siteURL = getSite().getURL();
+ if (siteURL == null) {
+ UpdateCore.warn("Unable to create marker. The Site url is null."); //$NON-NLS-1$
+ return false;
+ }
+
+ if (!"file".equalsIgnoreCase(siteURL.getProtocol())) { //$NON-NLS-1$
+ UpdateCore.warn("Unable to create private marker. The Site is not on the local file system."); //$NON-NLS-1$
+ return false;
+ }
+
+ String siteLocation = siteURL.getFile();
+ File productFile = getProductFile();
+ boolean success = false;
+ if (productFile != null) {
+ String productId = getProductIdentifier("id", productFile); //$NON-NLS-1$
+ String productName = getProductIdentifier("name", productFile); //$NON-NLS-1$
+ String productVer = getProductIdentifier("version", productFile); //$NON-NLS-1$
+ if (productId != null) {
+ File file = new File(siteLocation, EXTENSION_SITE_MARKER);
+ if (!file.exists()) {
+ OutputStream out = null;
+ OutputStreamWriter outWriter = null;
+ try {
+ out = new FileOutputStream(file);
+ outWriter = new OutputStreamWriter(out, "UTF8"); //$NON-NLS-1$
+ outWriter.write("id=" + productId+"\n"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (productName != null)
+ outWriter.write("name=" + productName+"\n"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (productVer != null)
+ outWriter.write("version=" + productVer+"\n"); //$NON-NLS-1$ //$NON-NLS-2$
+ success = true;
+ justCreated = true;
+ } catch (Exception e) {
+ UpdateCore.warn("Unable to create private Marker at:" + file, e); //$NON-NLS-1$
+ } finally {
+ try {
+ if (outWriter != null)
+ outWriter.close();
+ } catch (IOException e1) {
+ }
+ try {
+ if (out != null)
+ out.close();
+ } catch (IOException e2) {
+ }
+ }
+ }
+ }
+ }
+ return success;
+ }
+
+
+ /*
+ * Returns true if the directory of the Site contains
+ * .eclipseextension
+ */
+ public boolean isExtensionSite() {
+ return containsMarker(EXTENSION_SITE_MARKER);
+ }
+
+ /*
+ * Returns true if the directory of the Site contains
+ * .eclipseextension
+ */
+ public boolean isProductSite() {
+ return containsMarker(PRODUCT_SITE_MARKER);
+ }
+
+ /*
+ * Returns true if the directory of the Site contains
+ * .eclipseextension
+ */
+ public boolean isPrivateSite() {
+ return isExtensionSite();
+ }
+
+ /*
+ *
+ */
+ private boolean containsMarker(String marker) {
+ ISite site = getSite();
+ if (site == null) {
+ UpdateCore.warn("Contains Markers:The site is null"); //$NON-NLS-1$
+ return false;
+ }
+
+ URL url = site.getURL();
+ if (url == null) {
+ UpdateCore.warn("Contains Markers:Site URL is null"); //$NON-NLS-1$
+ return false;
+ }
+ if (!"file".equalsIgnoreCase(url.getProtocol())) { //$NON-NLS-1$
+ UpdateCore.warn("Contains Markers:Non file protocol"); //$NON-NLS-1$
+ return false;
+ }
+ File file = new File(url.getFile());
+ if (!file.exists()) {
+ UpdateCore.warn("Contains Markers:The site doesn't exist:" + file); //$NON-NLS-1$
+ return false;
+ }
+ File extension = new File(file, marker);
+ if (!extension.exists()) {
+ UpdateCore.warn("Contains Markers:The extensionfile does not exist:" + extension); //$NON-NLS-1$
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * Returns true if the Site is already natively linked
+ */
+ public boolean isNativelyLinked() throws CoreException {
+ String platformString = getPlatformURLString();
+ if (platformString == null) {
+ UpdateCore.warn("Unable to retrieve platformString"); //$NON-NLS-1$
+ return false;
+ }
+
+ URL siteURL = null;
+ try {
+ // check if the site exists and is updateable
+ // update configSite
+ URL urlToCheck = new URL(platformString);
+ IPlatformConfiguration runtimeConfig = ConfiguratorUtils.getCurrentPlatformConfiguration();
+ IPlatformConfiguration.ISiteEntry entry = runtimeConfig.findConfiguredSite(urlToCheck);
+ if (entry != null) {
+ return entry.isNativelyLinked();
+ } else {
+ UpdateCore.warn("Unable to retrieve site:" + platformString + " from platform."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ // check by comparing URLs
+ IPlatformConfiguration.ISiteEntry[] sites = runtimeConfig.getConfiguredSites();
+ for (int i = 0; i < sites.length; i++) {
+ siteURL = sites[i].getURL();
+ URL resolvedURL = FileLocator.resolve(siteURL);
+ if (UpdateManagerUtils.sameURL(resolvedURL, urlToCheck))
+ return true;
+ }
+ } catch (MalformedURLException e) {
+ String msg = NLS.bind(Messages.ConfiguredSite_UnableResolveURL, (new String[] { platformString }));
+ throw Utilities.newCoreException(msg, e);
+ } catch (IOException e) {
+ String msg = NLS.bind(Messages.ConfiguredSite_UnableToAccessSite, (new Object[] { siteURL }));
+ throw Utilities.newCoreException(msg, e);
+ }
+
+ return false;
+ }
+
+ /*
+ * we have to check that no configured/enable parent include this feature
+ */
+ private boolean validateNoConfiguredParents(IFeature feature) throws CoreException {
+ if (feature == null) {
+ UpdateCore.warn("ConfigurationPolicy: validate Feature is null"); //$NON-NLS-1$
+ return true;
+ }
+
+ IFeatureReference[] parents = UpdateManagerUtils.getParentFeatures(feature, getConfiguredFeatures(), false);
+ return (parents.length == 0);
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ContentConsumer.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ContentConsumer.java
new file mode 100644
index 0000000..5278a7c
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ContentConsumer.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+
+
+import org.eclipse.update.core.*;
+
+/**
+ * A default implementation for IFeatureContentConsumer
+ * </p>
+ * @since 2.0
+ */
+
+public abstract class ContentConsumer implements IContentConsumer {
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/CoreExceptionWithRootCause.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/CoreExceptionWithRootCause.java
new file mode 100644
index 0000000..d822959
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/CoreExceptionWithRootCause.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * 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.update.internal.core;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+
+public class CoreExceptionWithRootCause extends CoreException {
+
+ private static final long serialVersionUID = 6832993239926767403L;
+
+ private Throwable e = null;
+
+ public CoreExceptionWithRootCause(IStatus status) {
+ super(status);
+ }
+
+ public void setRootException(Throwable e) {
+ this.e = e;
+ }
+
+ public Throwable getRootException() {
+ return e;
+ }
+
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/DefaultInstallHandler.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/DefaultInstallHandler.java
new file mode 100644
index 0000000..5029b04
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/DefaultInstallHandler.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+
+
+import java.io.*;
+import java.util.jar.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+import org.eclipse.update.core.JarContentReference.*;
+import org.eclipse.update.core.model.*;
+
+/**
+ * Default Implementation of InstallHandler
+ */
+public class DefaultInstallHandler extends BaseInstallHandler {
+
+ /*
+ * @see IInstallHandler#nonPluginDataDownloaded(INonPluginEntry[], IVerificationListener)
+ */
+ public void nonPluginDataDownloaded(
+ INonPluginEntry[] nonPluginData,
+ IVerificationListener listener)
+ throws CoreException {
+
+ // verify non-plugin archives. The DefaultInstallHandler assumes
+ // the verifier associated with the feature is able to verify the
+ // data archives.
+ if (nonPluginData == null || nonPluginData.length == 0)
+ return;
+
+ this.nonPluginEntries = nonPluginData;
+ IFeatureContentProvider provider = this.feature.getFeatureContentProvider();
+ IVerifier verifier = provider.getVerifier();
+ if (verifier == null)
+ return;
+
+ for (int i = 0; i < this.nonPluginEntries.length; i++) {
+ ContentReference[] archives =
+ provider.getNonPluginEntryArchiveReferences(nonPluginEntries[i], this.monitor);
+ IVerificationResult result;
+ for (int j = 0; j < archives.length; j++) {
+
+ // see if the data entry is a jar
+ ContentReference archive = archives[j];
+ if (!(archives[j] instanceof JarContentReference)
+ && archives[j].getIdentifier().endsWith(".jar")) { //$NON-NLS-1$
+ try {
+ archive =
+ new JarContentReference(archives[j].getIdentifier(), archives[j].asFile());
+ } catch (IOException e) {
+ }
+ }
+
+ result = verifier.verify(this.feature, archive, false, this.monitor);
+ if (result != null)
+ promptForVerification(result, listener);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallHandler#completeInstall(IFeatureContentConsumer)
+ */
+ public void completeInstall(IFeatureContentConsumer consumer)
+ throws CoreException {
+
+ // plugins have been installed. Check to see if we have any
+ // non-plugin entries that need to be handled.
+ if (this.nonPluginEntries == null || this.nonPluginEntries.length == 0)
+ return;
+
+ // install non-plugin archives
+ IFeatureContentProvider provider = this.feature.getFeatureContentProvider();
+ for (int i = 0; i < this.nonPluginEntries.length; i++) {
+ ContentReference[] archive =
+ provider.getNonPluginEntryArchiveReferences(nonPluginEntries[i], this.monitor);
+ IContentConsumer nonPluginConsumer = consumer.open(nonPluginEntries[i]);
+ for (int j = 0; j < archive.length; j++) {
+ String id = archive[j].getIdentifier();
+ if (id.endsWith(".jar")) { //$NON-NLS-1$
+ // the non-plugin archive is a jar. Unpack it into
+ // a directory constructed using the archive id
+ try {
+ final String prefix = id.substring(0, id.length() - 4) + "/"; //$NON-NLS-1$
+ JarContentReference jarRef = new JarContentReference("", archive[j].asFile()); //$NON-NLS-1$
+ ContentSelector selector = new ContentSelector() {
+ public String defineIdentifier(JarEntry entry) {
+ if (entry == null)
+ return null;
+ else
+ return prefix + entry.getName();
+ }
+ };
+ ContentReference[] entries = jarRef.peek(selector, this.monitor);
+ for (int k = 0; k < entries.length; k++) {
+ nonPluginConsumer.store(entries[k], this.monitor);
+ }
+ } catch (IOException e) {
+ throw Utilities
+ .newCoreException(NLS.bind(Messages.JarVerificationService_CancelInstall, (new String[] { id })),
+ e);
+ }
+
+ } else {
+ // the non-plugin archive is not a jar. Install it asis.
+ nonPluginConsumer.store(archive[j], this.monitor);
+ }
+ }
+ nonPluginConsumer.close();
+ }
+ }
+
+ /*
+ *
+ */
+ private void promptForVerification(
+ IVerificationResult verificationResult,
+ IVerificationListener listener)
+ throws CoreException {
+
+ if (listener == null)
+ return;
+ int result = listener.prompt(verificationResult);
+
+ if (result == IVerificationListener.CHOICE_ABORT) {
+ Exception e = verificationResult.getVerificationException();
+ throw new InstallAbortedException(Messages.JarVerificationService_CancelInstall,e);
+ }
+ if (result == IVerificationListener.CHOICE_ERROR) {
+ throw Utilities
+ .newCoreException(Messages.JarVerificationService_UnsucessfulVerification,
+ verificationResult.getVerificationException());
+ }
+
+ return;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/DeltaInstallHandler.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/DeltaInstallHandler.java
new file mode 100644
index 0000000..d92d735
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/DeltaInstallHandler.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.core;
+
+import org.eclipse.core.runtime.IStatus;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.update.core.BaseInstallHandler;
+import org.eclipse.update.core.ContentReference;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IFeatureContentConsumer;
+import org.eclipse.update.core.IPluginEntry;
+import org.eclipse.update.core.PluginEntry;
+import org.eclipse.update.core.Site;
+import org.eclipse.update.internal.operations.UpdateUtils;
+
+/**
+ * Install handler for partial plugin delivery: copy delta content from old plugin into the new one.
+ * The new plugin should only contain files that have changed.
+ */
+public class DeltaInstallHandler extends BaseInstallHandler {
+ private final static String PLUGIN_XML = "plugin.xml"; //$NON-NLS-1$
+ private final static String FRAGMENT_XML = "fragment.xml"; //$NON-NLS-1$
+ private final static String META_MANIFEST = "META-INF/MANIFEST.MF"; //$NON-NLS-1$
+
+ protected IFeature oldFeature;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.core.IInstallHandler#completeInstall(org.eclipse.update.core.IFeatureContentConsumer)
+ */
+ public void completeInstall(IFeatureContentConsumer consumer)
+ throws CoreException {
+ try {
+ if (pluginEntries == null)
+ return;
+
+ if (!feature.isPatch()) {
+ // Get the old feature
+ IFeature[] oldFeatures = UpdateUtils
+ .getInstalledFeatures(feature);
+ if (oldFeatures.length == 0)
+ return;
+ oldFeature = oldFeatures[0];
+ } else {
+ oldFeature = UpdateUtils.getPatchedFeature(feature);
+ if (oldFeature == null) {
+ return;
+ }
+ }
+
+ IPluginEntry[] oldPlugins = oldFeature.getPluginEntries();
+ for (int i = 0; i < pluginEntries.length; i++) {
+ IPluginEntry newPlugin = pluginEntries[i];
+ IPluginEntry oldPlugin =
+ getPluginEntry(
+ oldPlugins,
+ newPlugin.getVersionedIdentifier().getIdentifier());
+ if (oldPlugin == null)
+ continue;
+ try {
+ overlayPlugin(oldPlugin, newPlugin, consumer);
+ } catch (IOException e) {
+ throw new CoreException(
+ new Status(
+ IStatus.ERROR,
+ UpdateUtils.getPluginId(),
+ 1,
+ "", //$NON-NLS-1$
+ e));
+ }
+ }
+ } finally {
+ //if (contentConsumer != null)
+ // contentConsumer.close();
+ }
+ }
+
+ protected IPluginEntry getPluginEntry(IPluginEntry[] plugins, String id) {
+ for (int i = 0; i < plugins.length; i++)
+ if (plugins[i].getVersionedIdentifier().getIdentifier().equals(id))
+ return plugins[i];
+ return null;
+ }
+
+ protected boolean referenceExists(
+ ContentReference[] references,
+ ContentReference ref) {
+ String id = ref.getIdentifier();
+ if (id == null)
+ return false;
+
+ for (int i = 0; i < references.length; i++)
+ if (id.equals(references[i].getIdentifier()))
+ return true;
+ return false;
+ }
+
+ protected void overlayPlugin(
+ IPluginEntry oldPlugin,
+ IPluginEntry newPlugin,
+ IFeatureContentConsumer consumer)
+ throws CoreException, IOException {
+ if(newPlugin instanceof PluginEntry && !((PluginEntry)newPlugin).isUnpack()){
+ // partial plug-ins (in patches) must always be unpacked
+ return;
+ }
+
+ // copy the content of the old plugin over the new one, but only
+ // those files that do not exist on the target
+ ContentReference[] oldReferences =
+ oldFeature
+ .getFeatureContentProvider()
+ .getPluginEntryContentReferences(
+ oldPlugin,
+ null);
+ ContentReference[] newReferences =
+ feature
+ .getFeatureContentProvider()
+ .getPluginEntryContentReferences(
+ newPlugin,
+ null);
+
+ URL newURL = new URL(consumer.getFeature().getSite().getURL(),
+ Site.DEFAULT_PLUGIN_PATH
+ + newPlugin.getVersionedIdentifier().toString());
+ String pluginPath = newURL.getFile();
+ for (int i = 0; i < oldReferences.length; i++) {
+ if (isPluginManifest(oldReferences[i])
+ || referenceExists(newReferences, oldReferences[i]))
+ continue;
+
+ InputStream input = null;
+ try {
+ input = oldReferences[i].getInputStream();
+ File targetFile =
+ new File(pluginPath, oldReferences[i].getIdentifier());
+ UpdateManagerUtils.copyToLocal(
+ input,
+ targetFile.getAbsolutePath(),
+ null);
+ UpdateManagerUtils.checkPermissions(
+ oldReferences[i],
+ pluginPath);
+ // 20305
+ } catch (IOException e) {
+ continue;
+ } finally {
+ if(input != null){
+ try{
+ input.close();
+ } catch (IOException ioe) {
+ }
+ }
+ }
+ }
+ }
+
+ protected boolean isPluginManifest(ContentReference ref) {
+ String id = ref.getIdentifier();
+ return PLUGIN_XML.equals(id) || FRAGMENT_XML.equals(id) || META_MANIFEST.equals(id);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/Digest.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/Digest.java
new file mode 100644
index 0000000..27e1616
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/Digest.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * 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.update.internal.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.update.core.JarContentReference;
+import org.eclipse.update.core.model.FeatureModel;
+import org.xml.sax.SAXException;
+
+public class Digest {
+
+ private URL source;
+ private File localSource;
+ private JarFile digestJar;
+ private InputStream inputStream;
+
+
+ public Digest(URL source){
+ this.source = source;
+ }
+
+ public FeatureModel[] parseDigest() throws IOException, CoreException, SAXException {
+ DigestContentProvider digestContentProvider = new DigestContentProvider(source);
+ localSource = digestContentProvider.asLocalReference(new JarContentReference( null, source), null).asFile();
+ digestJar = new JarFile(localSource);
+
+ ZipEntry digestEntry = digestJar.getEntry("digest.xml"); //$NON-NLS-1$
+
+ if (digestEntry != null) {
+ inputStream = digestJar.getInputStream(digestEntry);
+ DigestParser digest = new DigestParser();
+ digest.init(new LiteFeatureFactory());
+ return digest.parse(inputStream);
+ } else {
+ throw new CoreException(null);
+ }
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/DigestContentProvider.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/DigestContentProvider.java
new file mode 100644
index 0000000..ec848aa
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/DigestContentProvider.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * 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.update.internal.core;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.update.core.ContentReference;
+import org.eclipse.update.core.FeatureContentProvider;
+import org.eclipse.update.core.INonPluginEntry;
+import org.eclipse.update.core.IPluginEntry;
+import org.eclipse.update.core.IVerifier;
+import org.eclipse.update.core.InstallMonitor;
+
+public class DigestContentProvider extends FeatureContentProvider {
+
+ public DigestContentProvider(URL base) {
+ super(base);
+ // TODO Auto-generated constructor stub
+ }
+
+
+ public ContentReference asLocalReference( ContentReference ref,
+ InstallMonitor monitor) throws IOException, CoreException {
+ return super.asLocalReference(ref, monitor);
+ }
+
+ public ContentReference[] getArchiveReferences(InstallMonitor monitor)
+ throws CoreException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public ContentReference[] getFeatureEntryArchiveReferences(
+ InstallMonitor monitor) throws CoreException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public ContentReference[] getFeatureEntryContentReferences(
+ InstallMonitor monitor) throws CoreException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public ContentReference getFeatureManifestReference(InstallMonitor monitor)
+ throws CoreException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public ContentReference[] getNonPluginEntryArchiveReferences(
+ INonPluginEntry nonPluginEntry, InstallMonitor monitor)
+ throws CoreException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public ContentReference[] getPluginEntryArchiveReferences(
+ IPluginEntry pluginEntry, InstallMonitor monitor)
+ throws CoreException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public ContentReference[] getPluginEntryContentReferences(
+ IPluginEntry pluginEntry, InstallMonitor monitor)
+ throws CoreException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public IVerifier getVerifier() throws CoreException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/DigestParser.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/DigestParser.java
new file mode 100644
index 0000000..ca0782b
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/DigestParser.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * 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.update.internal.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.update.core.model.FeatureModelFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+public class DigestParser extends DefaultHandler {
+
+ private InternalFeatureParser featureParser;
+
+ private ArrayList featureModels;
+
+ private SAXParser parser;
+
+ private FeatureModelFactory factory;
+
+ private String location;
+
+ private final static SAXParserFactory parserFactory =
+ SAXParserFactory.newInstance();
+
+ public DigestParser() {
+ super();
+ featureParser = new InternalFeatureParser();
+ try {
+ parserFactory.setNamespaceAware(true);
+ this.parser = parserFactory.newSAXParser();
+ } catch (ParserConfigurationException e) {
+ UpdateCore.log(e);
+ } catch (SAXException e) {
+ UpdateCore.log(e);
+ }
+ }
+
+ public void init(FeatureModelFactory factory) {
+ init(factory, null);
+ }
+
+ /**
+ * @param factory
+ * @param location
+ * @since 3.1
+ */
+ public void init(FeatureModelFactory factory, String location) {
+
+ this.factory = factory;
+ this.location = location;
+ factory = new LiteFeatureFactory();
+ featureModels = new ArrayList();
+ featureParser.internalInit(factory, location);
+ }
+
+ /**
+ * Parses the specified input steam and constructs a feature model.
+ * The input stream is not closed as part of this operation.
+ *
+ * @param in input stream
+ * @return feature model
+ * @exception SAXException
+ * @exception IOException
+ * @since 2.0
+ */
+ public LiteFeature[] parse(InputStream in) throws SAXException, IOException {
+
+ parser.parse(new InputSource(in), this);
+ return (LiteFeature[])featureModels.toArray( new LiteFeature[featureModels.size()]);
+ }
+
+
+ /**
+ * Returns all status objects accumulated by the parser.
+ *
+ * @return multi-status containing accumulated status, or <code>null</code>.
+ * @since 2.0
+ */
+ public MultiStatus getStatus() {
+ return featureParser.getStatus();
+ }
+
+ /**
+ * Handle start of element tags
+ * @see DefaultHandler#startElement(String, String, String, Attributes)
+ * @since 2.0
+ */
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ if(localName.equals("digest")) //$NON-NLS-1$
+ return;
+ if(localName.equals("feature")) //$NON-NLS-1$
+ featureParser.internalInit(factory, location);
+
+ featureParser.startElement(uri, localName, qName, attributes);
+ }
+
+ /**
+ * Handle end of element tags
+ * @see DefaultHandler#endElement(String, String, String)
+ * @since 2.0
+ */
+ public void endElement(String uri, String localName, String qName) {
+ if(localName.equals("digest")) //$NON-NLS-1$
+ return;
+ featureParser.endElement(uri, localName, qName);
+ if(localName.equals("feature")) { //$NON-NLS-1$
+ try {
+ featureModels.add(featureParser.getFeatureModel());
+ } catch (SAXException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+
+ /**
+ * Handle character text
+ * @see DefaultHandler#characters(char[], int, int)
+ * @since 2.0
+ */
+ public void characters(char[] ch, int start, int length) {
+ featureParser.characters(ch, start, length);
+ }
+
+ /**
+ * Handle errors
+ * @see DefaultHandler#error(SAXParseException)
+ * @since 2.0
+ */
+ public void error(SAXParseException ex) {
+ featureParser.error(ex);
+ }
+
+ /**
+ * Handle fatal errors
+ * @see DefaultHandler#fatalError(SAXParseException)
+ * @exception SAXException
+ * @since 2.0
+ */
+ public void fatalError(SAXParseException ex) throws SAXException {
+ featureParser.fatalError(ex);
+ }
+
+ /**
+ * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
+ */
+ public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
+ featureParser.ignorableWhitespace(arg0, arg1, arg2);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/EmptyDirectoryException.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/EmptyDirectoryException.java
new file mode 100644
index 0000000..732e174
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/EmptyDirectoryException.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * 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.update.internal.core;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+
+public class EmptyDirectoryException extends CoreException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -762930667883265228L;
+
+ public EmptyDirectoryException(IStatus status) {
+ super(status);
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ErrorRecoveryLog.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ErrorRecoveryLog.java
new file mode 100644
index 0000000..d87764b
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ErrorRecoveryLog.java
@@ -0,0 +1,270 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.core;
+
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configurator.ConfiguratorUtils;
+import org.eclipse.update.configurator.IPlatformConfiguration;
+import org.eclipse.update.core.Utilities;
+
+
+/**
+ * Manages the error/recover log file
+ */
+public class ErrorRecoveryLog {
+ private static final String ERROR_RECOVERY_LOG = "error_recovery.log"; //$NON-NLS-1$
+ private static final String LOG_ENTRY_KEY = "LogEntry."; //$NON-NLS-1$
+ private static final String RETURN_CARRIAGE = "\r\n"; //$NON-NLS-1$
+ private static final String END_OF_FILE = "eof=eof"; //$NON-NLS-1$
+
+ //
+ public static final String START_INSTALL_LOG = "START_INSTALL_LOG"; //$NON-NLS-1$
+ public static final String PLUGIN_ENTRY = "PLUGIN"; //$NON-NLS-1$
+ public static final String FRAGMENT_ENTRY = "FRAGMENT"; //$NON-NLS-1$
+ public static final String BUNDLE_MANIFEST_ENTRY = "BUNDLE_MANIFEST"; //$NON-NLS-1$
+ public static final String BUNDLE_JAR_ENTRY = "BUNDLE"; //$NON-NLS-1$
+ public static final String FEATURE_ENTRY = "FEATURE"; //$NON-NLS-1$2
+ public static final String ALL_INSTALLED = "ALL_FEATURES_INSTALLED"; //$NON-NLS-1$
+ public static final String RENAME_ENTRY = "RENAME"; //$NON-NLS-1$
+ public static final String END_INSTALL_LOG = "END_INSTALL_LOG"; //$NON-NLS-1$
+ public static final String START_REMOVE_LOG = "REMOVE_LOG"; //$NON-NLS-1$
+ public static final String END_ABOUT_REMOVE = "END_ABOUT_TO_REMOVE"; //$NON-NLS-1$
+ public static final String DELETE_ENTRY = "DELETE"; //$NON-NLS-1$
+ public static final String END_REMOVE_LOG = "END_REMOVE_LOG"; //$NON-NLS-1$
+
+ private static ErrorRecoveryLog inst;
+ private FileWriter out;
+ private int index;
+ private List paths;
+
+ private boolean open = false;
+ private int nbOfOpen = 0;
+
+
+ /**
+ * Constructor for ErrorRecoveryLog.
+ */
+ private ErrorRecoveryLog() {
+ super();
+ }
+
+ /**
+ * Singleton
+ */
+ public static ErrorRecoveryLog getLog() {
+ if (inst == null){
+ inst = new ErrorRecoveryLog();
+ }
+ return inst;
+ }
+
+ /**
+ * get a unique identifer for the file, ensure uniqueness up to now
+ */
+ public static String getLocalRandomIdentifier(String path) {
+
+ if (path==null) return null;
+
+ // verify if it will be a directory without creating the file
+ // as it doesn't exist yet
+ if (path.endsWith(File.separator) || path.endsWith("/")) //$NON-NLS-1$
+ return path;
+ File file = new File(path);
+ String newName =
+ UpdateManagerUtils.getLocalRandomIdentifier(file.getName(), new Date());
+ while (new File(file.getParentFile(), newName).exists()) {
+ newName =
+ UpdateManagerUtils.getLocalRandomIdentifier(file.getName(), new Date());
+ }
+ File newFile = new File(file.getParentFile(),newName);
+ return newFile.getAbsolutePath();
+ }
+
+ /**
+ * returns the log file
+ * We do not check if the file exists
+ */
+ public File getRecoveryLogFile() {
+ IPlatformConfiguration configuration =
+ ConfiguratorUtils.getCurrentPlatformConfiguration();
+ URL location = configuration.getConfigurationLocation();
+ String locationString = location.getFile();
+ File platformConfiguration = new File(locationString);
+ if (!platformConfiguration.isDirectory()) platformConfiguration = platformConfiguration.getParentFile();
+ return new File(platformConfiguration, ERROR_RECOVERY_LOG);
+ }
+
+
+ /**
+ * Open the log
+ */
+ public void open(String logEntry) throws CoreException {
+ if (open) {
+ nbOfOpen++;
+ UpdateCore.warn("Open nested Error/Recovery log #"+nbOfOpen+":"+logEntry); //$NON-NLS-1$ //$NON-NLS-2$
+ return;
+ }
+
+ File logFile = null;
+ try {
+ logFile = getRecoveryLogFile();
+ out = new FileWriter(logFile);
+ index = 0;
+ paths=null;
+ open=true;
+ nbOfOpen=0;
+ UpdateCore.warn("Start new Error/Recovery log #"+nbOfOpen+":"+logEntry); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (IOException e) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.UpdateManagerUtils_UnableToLog, (new Object[] { logFile })),
+ e);
+ }
+
+ append(logEntry);
+ }
+
+ /**
+ * Append the string to the log and flush
+ */
+ public void append(String logEntry) throws CoreException {
+ File logFile = null;
+ try {
+ if (!open) {
+ UpdateCore.warn("Internal Error: The Error/Recovery log is not open:"+logEntry); //$NON-NLS-1$
+ return;
+ }
+
+ StringBuffer buffer = new StringBuffer(LOG_ENTRY_KEY);
+ buffer.append(index);
+ buffer.append("="); //$NON-NLS-1$
+ buffer.append(logEntry);
+ buffer.append(RETURN_CARRIAGE);
+
+ out.write(buffer.toString());
+ out.flush();
+ index++;
+ } catch (IOException e) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.UpdateManagerUtils_UnableToLog, (new Object[] { logFile })),
+ e);
+ }
+ }
+
+ /**
+ * Append the string to the log and flush
+ */
+ public void appendPath(String logEntry, String path) throws CoreException {
+ if (path == null)
+ return;
+ StringBuffer buffer = new StringBuffer(logEntry);
+ buffer.append(" "); //$NON-NLS-1$
+ buffer.append(path);
+ append(buffer.toString());
+
+ addPath(path);
+ }
+
+ /**
+ * Close any open recovery log
+ */
+ public void close(String logEntry) throws CoreException {
+
+ if (nbOfOpen>0){
+ UpdateCore.warn("Close nested Error/Recovery log #"+nbOfOpen+":"+logEntry); //$NON-NLS-1$ //$NON-NLS-2$
+ nbOfOpen--;
+ return;
+ }
+
+ UpdateCore.warn("Close Error/Recovery log #"+nbOfOpen+":"+logEntry); //$NON-NLS-1$ //$NON-NLS-2$
+ append(logEntry);
+ if (out != null) {
+ try {
+ out.write(END_OF_FILE);
+ out.flush();
+ out.close();
+ } catch (IOException e) { //eat the exception
+ } finally {
+ out = null;
+ open=false;
+ }
+ }
+ }
+
+ /**
+ * Delete the file from the file system
+ */
+ public void delete() {
+ //File logFile = getRecoveryLogFile();
+ getRecoveryLogFile();
+ //if (logFile.exists())
+ //logFile.delete();
+ }
+
+ /**
+ *
+ */
+ private void addPath(String path){
+ if (paths==null) paths = new ArrayList();
+ paths.add(path);
+ }
+
+ /*
+ * creates a Status
+ */
+ private IStatus createStatus(int statusSeverity, String msg, Exception e){
+ String id =
+ UpdateCore.getPlugin().getBundle().getSymbolicName();
+
+ StringBuffer completeString = new StringBuffer(""); //$NON-NLS-1$
+ if (msg!=null)
+ completeString.append(msg);
+ if (e!=null){
+ completeString.append("\r\n["); //$NON-NLS-1$
+ completeString.append(e.toString());
+ completeString.append("]\r\n"); //$NON-NLS-1$
+ }
+ return new Status(statusSeverity, id, IStatus.OK, completeString.toString(), e);
+ }
+
+ /**
+ * return a multi status,
+ * the children are the file that couldn't be removed
+ */
+ public IStatus removeFromFileSystem(File file) {
+
+ IStatus mainStatus = createStatus(IStatus.OK,"",null); //$NON-NLS-1$
+ MultiStatus multi = new MultiStatus(mainStatus.getPlugin(),mainStatus.getCode(),"",null); //$NON-NLS-1$
+
+ if (!file.exists()){
+ multi.add(createStatus(IStatus.ERROR,Messages.ErrorRecoveryLog_noFiletoRemove+file,null));
+ return multi;
+ }
+
+ if (file.isDirectory()) {
+ String[] files = file.list();
+ if (files != null) // be careful since file.list() can return null
+ for (int i = 0; i < files.length; ++i){
+ multi.addAll(removeFromFileSystem(new File(file, files[i])));
+ }
+ }
+
+ if (!file.delete()) {
+ String msg = "Unable to remove file" +file.getAbsolutePath(); //$NON-NLS-1$
+ multi.add(createStatus(IStatus.ERROR,msg,null));
+ }
+ return multi;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ExtendedSite.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ExtendedSite.java
new file mode 100644
index 0000000..b010bab
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ExtendedSite.java
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.update.core.IURLEntry;
+import org.eclipse.update.core.VersionedIdentifier;
+import org.eclipse.update.internal.model.SiteWithTimestamp;
+
+public class ExtendedSite extends SiteWithTimestamp /*Site*/ {
+
+ private boolean digestExist;
+ private String[] availableLocals;
+ private String digestURL;
+ private LiteFeature[] liteFeatures;
+ private LiteFeature[] allLiteFeatures;
+ private IURLEntry[] associateSites;
+ private boolean pack200 = false;
+ private IURLEntry selectedMirror;
+
+
+ public String getDigestURL() {
+ return digestURL;
+ }
+ public void setDigestURL(String digestURL) {
+ this.digestURL = digestURL;
+ }
+
+ public String[] getAvailableLocals() {
+ return availableLocals;
+ }
+ public void setAvailableLocals(String[] availableLocals) {
+ this.availableLocals = availableLocals;
+ }
+ public boolean isDigestExist() {
+ return digestExist;
+ }
+ public void setDigestExist(boolean digestExist) {
+ this.digestExist = digestExist;
+ }
+ public LiteFeature[] getLiteFeatures() {
+ if (getCurrentConfiguredSite()!=null)
+ return filterFeatures(getNonFilteredLiteFeatures());
+ else
+ return getNonFilteredLiteFeatures();
+ }
+ public void setLiteFeatures(LiteFeature[] liteFeatures) {
+
+ if ((liteFeatures == null) || (liteFeatures.length == 0))
+ return;
+ this.allLiteFeatures = liteFeatures;
+ List temp = new ArrayList();
+ for(int i = 0; i < allLiteFeatures.length ; i++) {
+ if (getFeatureReference(allLiteFeatures[i]) != null) {
+ temp.add(allLiteFeatures[i]);
+ }
+ }
+ if (!temp.isEmpty()) {
+ this.liteFeatures = (LiteFeature[])temp.toArray( new LiteFeature[temp.size()]);
+ }
+ }
+
+ public LiteFeature getLiteFeature(VersionedIdentifier vid) {
+ if (allLiteFeatures == null)
+ return null;
+
+ for(int i = 0; i < allLiteFeatures.length ; i++) {
+ if (vid.equals(allLiteFeatures[i].getVersionedIdentifier())) {
+ return allLiteFeatures[i];
+ }
+ }
+ return null;
+ }
+
+ public LiteFeature[] getNonFilteredLiteFeatures() {
+ return liteFeatures;
+ }
+ public void setNonFilteredLiteFeatures(LiteFeature[] liteFeatures) {
+ this.liteFeatures = liteFeatures;
+ }
+
+
+ /**
+ * Get whether or not this site may contain jars packed with pack200.
+ * The packed version of foo.jar, is expected to be foo.jar.pack.gz
+ * @return
+ */
+ public boolean supportsPack200() {
+ return pack200;
+ }
+
+ /**
+ * Set whether or not this site may contain jars packed with pack200
+ * The packed version of foo.jar is expected to be foo.jar.pack.gz
+ * @param pack
+ */
+ public void setSupportsPack200(boolean pack){
+ pack200 = pack;
+ }
+
+ /*
+ * Method filterFeatures.
+ * Also implemented in Feature
+ *
+ * @param list
+ * @return List
+ */
+ private LiteFeature[] filterFeatures(LiteFeature[] allIncluded) {
+ List list = new ArrayList();
+ if (allIncluded!=null){
+ for (int i = 0; i < allIncluded.length; i++) {
+ LiteFeature included = allIncluded[i];
+ if (UpdateManagerUtils.isValidEnvironment(included))
+ list.add(included);
+ else{
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_WARNINGS){
+ UpdateCore.warn("Filtered out feature reference:"+included); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ LiteFeature[] result = new LiteFeature[list.size()];
+ if (!list.isEmpty()){
+ list.toArray(result);
+ }
+
+ return result;
+ }
+ public IURLEntry[] getAssociateSites() {
+ return associateSites;
+ }
+ public void setAssociateSites(IURLEntry[] associateSites) {
+ this.associateSites = associateSites;
+ }
+
+ public IURLEntry getSelectedMirror() {
+ return selectedMirror;
+ }
+
+ public void setSelectedMirror(IURLEntry selectedMirror) {
+ this.selectedMirror = selectedMirror;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ExtendedSiteURLFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ExtendedSiteURLFactory.java
new file mode 100644
index 0000000..bea3981
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ExtendedSiteURLFactory.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * 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.update.internal.core;
+
+import org.eclipse.update.core.model.SiteModel;
+
+public class ExtendedSiteURLFactory extends SiteURLFactory {
+
+ public SiteModel createSiteMapModel() {
+ return new ExtendedSite();
+ }
+
+
+ //public SiteFeatureReferenceModel createFeatureReferenceModel() {
+ // return new UpdateSiteLiteFeatureReference();
+ //}
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FatalIOException.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FatalIOException.java
new file mode 100644
index 0000000..b82ee06
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FatalIOException.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * 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.update.internal.core;
+
+import java.io.IOException;
+
+public class FatalIOException extends IOException {
+ private static final long serialVersionUID = 7690318087505479039L;
+
+ public FatalIOException(String string) {
+ super(string);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureContentConsumer.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureContentConsumer.java
new file mode 100644
index 0000000..278de69
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureContentConsumer.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+
+
+import org.eclipse.update.core.*;
+import org.eclipse.update.core.model.*;
+
+/**
+ * A default implementation for IFeatureContentConsumer
+ * </p>
+ * @since 2.0
+ */
+
+public abstract class FeatureContentConsumer extends ModelObject
+ implements IFeatureContentConsumer {
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureDownloadException.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureDownloadException.java
new file mode 100644
index 0000000..cef1d61
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureDownloadException.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+
+import org.eclipse.core.runtime.*;
+
+/**
+ * Exception thrown when IOException during downloading features
+ *
+ * @since 3.0
+ */
+public class FeatureDownloadException extends CoreException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct the exception indicating enclosing CoreException
+ *
+ * @since 3.0
+ */
+ public FeatureDownloadException(String msg, Exception e) {
+ super(
+ new Status(
+ IStatus.INFO,
+ "org.eclipse.update.core", //$NON-NLS-1$
+ IStatus.OK,
+ msg,
+ e));
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureEntryWrapper.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureEntryWrapper.java
new file mode 100644
index 0000000..da1eca5
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureEntryWrapper.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * 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.update.internal.core;
+
+import org.eclipse.core.runtime.IProduct;
+import org.eclipse.update.internal.configurator.FeatureEntry;
+import org.osgi.framework.Bundle;
+
+/**
+ * Class used to wrapper feature entry objects. This class is necessary
+ * to remove the depedancy of the org.eclipse.update.configurator on
+ * the org.eclipse.core.runtime bundle.
+ *
+ * @since 3.2
+ */
+public class FeatureEntryWrapper implements IProduct {
+
+ private FeatureEntry entry;
+
+ /*
+ * Constructor for the class.
+ */
+ public FeatureEntryWrapper(FeatureEntry entry) {
+ super();
+ this.entry = entry;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IProduct#getApplication()
+ */
+ public String getApplication() {
+ return entry.getApplication();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IProduct#getName()
+ */
+ public String getName() {
+ return entry.getName();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IProduct#getDescription()
+ */
+ public String getDescription() {
+ return entry.getDescription();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IProduct#getId()
+ */
+ public String getId() {
+ return entry.getId();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IProduct#getProperty(java.lang.String)
+ */
+ public String getProperty(String key) {
+ return entry.getProperty(key);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IProduct#getDefiningBundle()
+ */
+ public Bundle getDefiningBundle() {
+ return entry.getDefiningBundle();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureExecutableContentConsumer.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureExecutableContentConsumer.java
new file mode 100644
index 0000000..8226d87
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureExecutableContentConsumer.java
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.update.core.ContentReference;
+import org.eclipse.update.core.IContentConsumer;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IFeatureContentConsumer;
+import org.eclipse.update.core.IFeatureReference;
+import org.eclipse.update.core.INonPluginEntry;
+import org.eclipse.update.core.IPluginEntry;
+
+/**
+ * ContentConsumer Implementation for a FeatureExecutable
+ */
+
+public class FeatureExecutableContentConsumer extends FeatureContentConsumer {
+
+ private IFeature feature;
+ private boolean closed= false;
+ private boolean aborted= false;
+ private ISiteContentConsumer contentConsumer;
+ private IFeatureContentConsumer parent = null;
+ private List /* of IFeatureContentCOnsumer */ children;
+
+ /*
+ * @see IContentConsumer#open(INonPluginEntry)
+ */
+ public IContentConsumer open(INonPluginEntry nonPluginEntry)
+ throws CoreException {
+ ContentConsumer cons = new NonPluginEntryContentConsumer(
+ getContentConsumer().open(nonPluginEntry));
+ return cons;
+ }
+
+ /*
+ * @see IContentConsumer#open(IPluginEntry)
+ */
+ public IContentConsumer open(IPluginEntry pluginEntry) throws CoreException {
+ ContentConsumer cons = new PluginEntryContentConsumer(getContentConsumer().open(pluginEntry));
+ return cons;
+ }
+
+ /*
+ * @see IContentConsumer#addChild(IFeature)
+ */
+ public void addChild(IFeature child) throws CoreException {
+ IFeatureContentConsumer childConsumer = child.getFeatureContentConsumer();
+ childConsumer.setParent(this);
+ if (children==null) children = new ArrayList();
+ children.add(childConsumer);
+ return;
+ }
+
+
+ /*
+ * @see IFeatureContentConsumer#store(ContentReference, IProgressMonitor)
+ */
+ public void store(ContentReference contentReference, IProgressMonitor monitor)
+ throws CoreException {
+ getContentConsumer().store(contentReference, monitor);
+ }
+
+ /*
+ * @see IFeatureContentConsumer#close()
+ */
+ public IFeatureReference close() throws CoreException {
+
+ if (!closed && getParent()!=null){
+ closed=true;
+ return null;
+ }
+
+ // parent consumer, log we are about to rename
+ // log files have been downloaded
+ if (getParent()==null){
+ ErrorRecoveryLog.getLog().append(ErrorRecoveryLog.ALL_INSTALLED);
+ }
+
+ IFeatureReference ref= null;
+ if (contentConsumer != null)
+ ref = contentConsumer.close();
+
+ // close nested feature
+ IFeatureContentConsumer[] children = getChildren();
+ for (int i = 0; i < children.length; i++) {
+ children[i].close();
+ }
+
+ return ref;
+ }
+
+ /*
+ * @see IFeatureContentConsumer#setFeature(IFeature)
+ */
+ public void setFeature(IFeature feature) {
+ this.feature= feature;
+ }
+
+ /*
+ * Sets the parent
+ */
+ public void setParent(IFeatureContentConsumer featureContentConsumer) {
+ this.parent= featureContentConsumer;
+ }
+
+ /*
+ * returns the Content Consumer for the feature
+ *
+ * Right now we are the only one to implement SiteContentConsumer
+ * Need to be exposed as API post v2.0
+ */
+ private ISiteContentConsumer getContentConsumer() throws CoreException {
+ if (contentConsumer == null)
+ if (feature.getSite() instanceof SiteFile) {
+ SiteFile site= (SiteFile) feature.getSite();
+ contentConsumer= site.createSiteContentConsumer(feature);
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ return contentConsumer;
+ }
+
+ /*
+ * @see IFeatureContentConsumer#abort()
+ */
+ public void abort() throws CoreException {
+
+ if (aborted) return;
+
+ IFeatureContentConsumer[] children = getChildren();
+ for (int i = 0; i < children.length; i++) {
+ try {
+ children[i].abort();
+ } catch (Exception e){
+ //do Nothing
+ }
+ }
+
+ // do not close plugin and non plugin content consumer
+ // the contentConsumer will abort them
+ // we do not need to abort the NonPluginEntryContentConsumer and PluginEntryContentConsume
+
+ //implement the cleanup
+ if (contentConsumer!=null)
+ contentConsumer.abort();
+
+ aborted = true;
+ }
+
+ /*
+ * @see IFeatureContentConsumer#getFeature()
+ */
+ public IFeature getFeature(){
+ return feature;
+ }
+
+ /*
+ * @see IFeatureContentConsumer#getParent()
+ */
+ public IFeatureContentConsumer getParent(){
+ return parent;
+ }
+
+ /*
+ * @see IFeatureContentConsumer#getChildren()
+ */
+ public IFeatureContentConsumer[] getChildren(){
+ if (children==null || children.size() == 0)
+ return new IFeatureContentConsumer[0];
+
+ return (IFeatureContentConsumer[]) children.toArray(arrayTypeFor(children));
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureExecutableContentProvider.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureExecutableContentProvider.java
new file mode 100644
index 0000000..0bf4c71
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureExecutableContentProvider.java
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+
+import java.io.*;
+import java.net.*;
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+
+/**
+ * Default implementation of a Executable Feature Content Provider
+ */
+
+public class FeatureExecutableContentProvider extends FeatureContentProvider {
+
+ /*
+ * Constructor
+ */
+ public FeatureExecutableContentProvider(URL url) {
+ super(url);
+ }
+
+ /*
+ * Return the path for a pluginEntry
+ */
+ private String getPath(IPluginEntry pluginEntry)
+ throws IOException, CoreException {
+
+ // get the URL of the Archive file that contains the plugin entry
+ ISiteContentProvider provider = getFeature().getSite().getSiteContentProvider();
+ URL fileURL = provider.getArchiveReference(getPathID(pluginEntry));
+ String result = fileURL.getFile();
+
+ if (!result.endsWith(".jar") && !result.endsWith("/") && !result.endsWith(File.separator)) //$NON-NLS-1$ //$NON-NLS-2$
+ result += File.separator;
+ File pluginPath = new File(result);
+ if (!pluginPath.exists())
+ throw new IOException(
+ NLS.bind(Messages.FeatureExecutableContentProvider_FileDoesNotExist, (new String[] { result })));
+
+ return result;
+ }
+
+ /*
+ * Returns the path for the Feature
+ */
+ private String getFeaturePath() throws IOException {
+ String result = getFeature().getURL().getFile();
+
+ // return the list of all subdirectories
+ if (!(result.endsWith(File.separator) || result.endsWith("/"))) //$NON-NLS-1$
+ result += File.separator;
+ File pluginDir = new File(result);
+ if (!pluginDir.exists())
+ throw new IOException(
+ NLS.bind(Messages.FeatureExecutableContentProvider_FileDoesNotExist, (new String[] { result })));
+
+ return result;
+ }
+
+ /*
+ * Returns all the files under the directory
+ * Recursive call
+ */
+ private List getFiles(File dir) throws IOException {
+ List result = new ArrayList();
+
+ if (!dir.isDirectory()) {
+ String msg =
+ NLS.bind(Messages.FeatureExecutableContentProvider_InvalidDirectory, (new String[] { dir.getAbsolutePath() }));
+
+ throw new IOException(msg);
+
+ }
+
+ File[] files = dir.listFiles();
+ if (files != null)
+ for (int i = 0; i < files.length; ++i) {
+ if (files[i].isDirectory()) {
+ result.addAll(getFiles(files[i]));
+ } else {
+ result.add(files[i]);
+ }
+ }
+
+ return result;
+ }
+
+ /*
+ * @see IFeatureContentProvider#getVerifier()
+ */
+ public IVerifier getVerifier() throws CoreException {
+ return null;
+ }
+
+ /*
+ * @see IFeatureContentProvider#getFeatureManifestReference()
+ */
+ public ContentReference getFeatureManifestReference(InstallMonitor monitor)
+ throws CoreException {
+ ContentReference result = null;
+ try {
+ result = new ContentReference(Feature.FEATURE_XML, new URL(getURL(), Feature.FEATURE_XML));
+
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.FeatureExecutableContentProvider_UnableToCreateURLFor, (new String[] { getURL().toExternalForm() + " " + Feature.FEATURE_XML })), //$NON-NLS-1$
+ e);
+ }
+ return result;
+ }
+
+ /*
+ * @see IFeatureContentProvider#getArchiveReferences()
+ */
+ public ContentReference[] getArchiveReferences(InstallMonitor monitor)
+ throws CoreException {
+ // executable feature does not contain archives
+ return new ContentReference[0];
+ }
+
+ /*
+ * @see IFeatureContentProvider#getPluginEntryArchiveReferences(IPluginEntry)
+ */
+ public ContentReference[] getPluginEntryArchiveReferences(
+ IPluginEntry pluginEntry,
+ InstallMonitor monitor)
+ throws CoreException {
+ ContentReference[] result = new ContentReference[1];
+ String archiveID = getPathID(pluginEntry);
+ try {
+ File archiveFile = new File(getPath(pluginEntry));
+ if(!archiveFile.isDirectory() && archiveFile.getName().endsWith(".jar")){ //$NON-NLS-1$
+ result[0] = new JarContentReference(archiveID, archiveFile);
+ } else {
+ result[0] =
+ new ContentReference(archiveID, archiveFile);
+ }
+ } catch (IOException e) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.FeatureExecutableContentProvider_UnableToRetrievePluginEntry, (new String[] { pluginEntry.getVersionedIdentifier().toString() })),
+ e);
+ }
+ return result;
+ }
+
+ /*
+ * @see IFeatureContentProvider#getNonPluginEntryArchiveReferences(INonPluginEntry)
+ */
+ public ContentReference[] getNonPluginEntryArchiveReferences(
+ INonPluginEntry nonPluginEntry,
+ InstallMonitor monitor)
+ throws CoreException {
+
+ ContentReference[] result = new ContentReference[1];
+ URL fileURL;
+
+ //try {
+ // get the URL of the Archive file that contains the plugin entry
+ ISiteContentProvider provider = getFeature().getSite().getSiteContentProvider();
+ fileURL = provider.getArchiveReference(getPathID(nonPluginEntry));
+
+ String fileString = fileURL.getFile();
+ File nonPluginData = new File(fileString);
+ if (!nonPluginData.exists())
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.FeatureExecutableContentProvider_FileDoesNotExist, (new String[] { fileString })),
+ null);
+
+ try {
+ result[0] =
+ new ContentReference(nonPluginEntry.getIdentifier(), nonPluginData.toURL());
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.FeatureExecutableContentProvider_UnableToRetrieveNonPluginEntry, (new String[] { nonPluginEntry.getIdentifier().toString() })),
+ e);
+ }
+ return result;
+ }
+
+ /*
+ * @see IFeatureContentProvider#getFeatureEntryArchiveReferences()
+ */
+ public ContentReference[] getFeatureEntryArchiveReferences(InstallMonitor monitor)
+ throws CoreException {
+ ContentReference[] contentReferences = new ContentReference[1];
+ contentReferences[0] = new ContentReference(null, getURL());
+ return contentReferences;
+ }
+
+ /*
+ * @see IFeatureContentProvider#getFeatureEntryArchivesContentReferences()
+ */
+ public ContentReference[] getFeatureEntryContentReferences(InstallMonitor monitor)
+ throws CoreException {
+ ContentReference[] result = new ContentReference[0];
+ try {
+ File featureDir = new File(getFeaturePath());
+ List files = getFiles(featureDir);
+ result = new ContentReference[files.size()];
+ for (int i = 0; i < result.length; i++) {
+ File currentFile = (File) files.get(i);
+ result[i] = new ContentReference(currentFile.getName(), currentFile.toURL());
+ }
+ } catch (IOException e) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.FeatureExecutableContentProvider_UnableToRetrieveFeatureEntry, (new String[] { getFeature().getVersionedIdentifier().toString() })),
+ e);
+ }
+ return result;
+ }
+
+ /*
+ * @see IFeatureContentProvider#getPluginEntryContentReferences(IPluginEntry)
+ */
+ public ContentReference[] getPluginEntryContentReferences(
+ IPluginEntry pluginEntry,
+ InstallMonitor monitor)
+ throws CoreException {
+
+ ContentReference[] references = getPluginEntryArchiveReferences(pluginEntry, monitor);
+ ContentReference[] result = new ContentReference[0];
+
+ try {
+ if (references[0] instanceof JarContentReference) {
+ result = ((JarContentReference)references[0]).peek(null, monitor);
+ } else {
+ // return the list of all subdirectories
+ File pluginDir = new File(getPath(pluginEntry));
+ URL pluginURL = pluginDir.toURL();
+ List files = getFiles(pluginDir);
+ result = new ContentReference[files.size()];
+ for (int i = 0; i < result.length; i++) {
+ File currentFile = (File) files.get(i);
+ String relativeString = UpdateManagerUtils.getURLAsString(pluginURL, currentFile.toURL());
+ result[i] = new ContentReference(relativeString, currentFile.toURL());
+ }
+ }
+ } catch (IOException e) {
+ throw Utilities.newCoreException(
+ Messages.FeatureExecutableContentProvider_UnableToRetriveArchiveContentRef
+ + pluginEntry.getVersionedIdentifier().toString(),
+ e);
+ }
+
+ //[20866] we did not preserve executable bit
+ validatePermissions(result);
+
+ return result;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureExecutableFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureExecutableFactory.java
new file mode 100644
index 0000000..170a688
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureExecutableFactory.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.BaseFeatureFactory;
+import org.eclipse.update.core.Feature;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IFeatureContentConsumer;
+import org.eclipse.update.core.IFeatureContentProvider;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.core.model.FeatureModel;
+import org.eclipse.update.internal.core.connection.ConnectionFactory;
+
+/**
+ * FeatureFactory for Executable Features
+ */
+public class FeatureExecutableFactory extends BaseFeatureFactory {
+
+ /*
+ * @see IFeatureFactory#createFeature(URL,ISite,IProgressMonitor)
+ */
+ public IFeature createFeature(URL url, ISite site, IProgressMonitor monitor) throws CoreException {
+
+ TargetFeature feature = null;
+ InputStream featureStream = null;
+ if (monitor == null)
+ monitor = new NullProgressMonitor();
+
+ if (url == null)
+ return createFeature(site);
+
+ // the URL should point to a directory
+ url = validate(url);
+
+ try {
+ IFeatureContentProvider contentProvider = new FeatureExecutableContentProvider(url);
+// // PERF: Do not create FeatureContentConsumer
+// bug 79893
+ IFeatureContentConsumer contentConsumer =new FeatureExecutableContentConsumer();
+
+ URL nonResolvedURL = contentProvider.getFeatureManifestReference(null).asURL();
+ URL resolvedURL = URLEncoder.encode(nonResolvedURL);
+ featureStream = ConnectionFactory.get(resolvedURL).getInputStream();
+
+ feature = (TargetFeature) this.parseFeature(featureStream, resolvedURL.toExternalForm());
+ monitor.worked(1);
+ feature.setSite(site);
+
+ feature.setFeatureContentProvider(contentProvider);
+// // PERF: FeatureContentConsumer
+// bug 79893
+ feature.setContentConsumer(contentConsumer);
+
+ feature.resolve(url, url);
+ feature.markReadOnly();
+ } catch (CoreException e) {
+ throw e;
+ } catch (Exception e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.FeatureFactory_CreatingError, (new String[] { url.toExternalForm() })), e);
+ } finally {
+ try {
+ if (featureStream != null)
+ featureStream.close();
+ } catch (IOException e) {
+ }
+ }
+ return feature;
+ }
+
+ /*
+ * @see FeatureModelFactory#createFeatureModel()
+ */
+ public FeatureModel createFeatureModel() {
+ return new TargetFeature();
+ }
+
+ /*
+ * Creates an empty feature on the site
+ */
+ private IFeature createFeature(ISite site) throws CoreException {
+ TargetFeature feature = null;
+
+ IFeatureContentProvider contentProvider = new FeatureExecutableContentProvider(null);
+ IFeatureContentConsumer contentConsumer = new FeatureExecutableContentConsumer();
+ feature = (TargetFeature) createFeatureModel();
+ feature.setSite(site);
+ feature.setFeatureContentProvider(contentProvider);
+ feature.setContentConsumer(contentConsumer);
+
+ // do not mark read only yet...
+ return feature;
+ }
+
+ /*
+ * validates a URL as a directory URL
+ */
+ private URL validate(URL url) throws CoreException {
+
+ if (url == null)
+ throw Utilities.newCoreException(Messages.FeatureExecutableFactory_NullURL, null);
+
+ if (!(url.getFile().endsWith("/") || url.getFile().endsWith(File.separator) || url.getFile().endsWith(Feature.FEATURE_XML))) { //$NON-NLS-1$
+ try {
+ String path = url.getFile() + "/"; //$NON-NLS-1$
+ url = new URL(url.getProtocol(), url.getHost(), url.getPort(), path);
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.FeatureExecutableFactory_CannotCreateURL, (new String[] { url.toExternalForm() })), e);
+ }
+ }
+ return url;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeaturePackagedContentProvider.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeaturePackagedContentProvider.java
new file mode 100644
index 0000000..03fc180
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeaturePackagedContentProvider.java
@@ -0,0 +1,466 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.core;
+
+import org.eclipse.update.core.FeatureContentProvider;
+
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.signedcontent.SignedContentFactory;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.jarprocessor.JarProcessor;
+import org.eclipse.update.internal.jarprocessor.Utils;
+import org.eclipse.update.internal.security.JarVerifier;
+import org.eclipse.update.internal.verifier.CertVerifier;
+
+/**
+ * Content Provider of a Feature Package
+ */
+public class FeaturePackagedContentProvider extends FeatureContentProvider {
+
+ private ContentReference localManifest = null;
+ private ContentReference[] localFeatureFiles = new ContentReference[0];
+ private IVerifier jarVerifier = null;
+ private ExtendedSite siteModel = null;
+ private boolean continueOnError;
+ /*
+ * filter for file with .jar
+ */
+ public static final FilenameFilter filter = new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(FeatureContentProvider.JAR_EXTENSION);
+ }
+ };
+
+ /*
+ * Constructor
+ */
+ public FeaturePackagedContentProvider(URL url, ISite site) {
+ super(url);
+ if (site instanceof ExtendedSite) {
+ this.siteModel = (ExtendedSite) site;
+ }
+ }
+
+ /*
+ * Returns a new verifier for each top-level install
+ * (if the verifier has a parent, return the verifier
+ * otherwise reinitialize)
+ */
+ public IVerifier getVerifier() throws CoreException {
+ SignedContentFactory factory = UpdateCore.getPlugin().getSignedContentFactory();
+ if (jarVerifier == null || jarVerifier.getParent() == null) {
+ if (factory != null)
+ jarVerifier = new CertVerifier(UpdateCore.getPlugin().getSignedContentFactory());
+ else
+ jarVerifier = new JarVerifier();
+ return jarVerifier;
+ }
+
+ // re-init will be done if the parent changes
+ return jarVerifier;
+ }
+
+ /*
+ * @see IFeatureContentProvider#getFeatureManifestReference()
+ */
+ public ContentReference getFeatureManifestReference(InstallMonitor monitor) throws CoreException {
+
+ // check to see if we already have local copy of the manifest
+ if (localManifest != null)
+ return localManifest;
+ ContentReference[] featureArchiveReference = getFeatureEntryArchiveReferences(monitor);
+ JarContentReference featureJarReference = null;
+ try {
+
+ // force feature archive to local.
+ // This content provider always assumes exactly 1 archive file (index [0])
+ featureJarReference = (JarContentReference) asLocalReference(featureArchiveReference[0], null);
+ // we need to unpack archive locally for UI browser references to be resolved correctly
+ localFeatureFiles = featureJarReference.unpack(getWorkingDirectory(), null, monitor);
+ } catch (IOException e) {
+ throw errorRetrieving(Feature.FEATURE_XML, featureJarReference, e);
+ }
+
+ // find the manifest in the unpacked feature files
+ for (int i = 0; i < localFeatureFiles.length; i++) {
+ if (localFeatureFiles[i].getIdentifier().equals(Feature.FEATURE_XML)) {
+ localManifest = localFeatureFiles[i];
+ // cache reference to manifest
+ return localManifest;
+ }
+ }
+
+ // the manifest has not been found
+ String[] values = new String[] { Feature.FEATURE_XML, getURL().toExternalForm()};
+ throw Utilities.newCoreException(NLS.bind(Messages.FeaturePackagedContentProvider_NoManifestFile, values), new Exception());
+
+ }
+
+ /*
+ * @see IFeatureContentProvider#getArchiveReferences()
+ */
+ public ContentReference[] getArchiveReferences(InstallMonitor monitor) throws CoreException {
+
+ IPluginEntry[] entries = getFeature().getPluginEntries();
+ INonPluginEntry[] nonEntries = getFeature().getNonPluginEntries();
+ List listAllContentRef = new ArrayList();
+ ContentReference[] allContentRef = new ContentReference[0];
+
+ // feature
+ listAllContentRef.addAll(Arrays.asList(getFeatureEntryArchiveReferences(monitor)));
+
+ // plugins
+ for (int i = 0; i < entries.length; i++) {
+ listAllContentRef.addAll(Arrays.asList(getPluginEntryArchiveReferences(entries[i], monitor)));
+ }
+
+ // non plugins
+ for (int i = 0; i < nonEntries.length; i++) {
+ listAllContentRef.addAll(Arrays.asList(getNonPluginEntryArchiveReferences(nonEntries[i], monitor)));
+ }
+
+ // transform List in Array
+ if (listAllContentRef.size() > 0) {
+ allContentRef = new ContentReference[listAllContentRef.size()];
+ listAllContentRef.toArray(allContentRef);
+ }
+
+ return allContentRef;
+ }
+
+ /*
+ * @see IFeatureContentProvider#getFeatureEntryArchiveReferences()
+ */
+ public ContentReference[] getFeatureEntryArchiveReferences(InstallMonitor monitor) throws CoreException {
+
+ //1 jar file <-> 1 feature
+ // we will return the JAR file
+ ContentReference[] references = new ContentReference[1];
+ ContentReference currentReference = null;
+ String archiveID = null;
+
+ try {
+ archiveID = (getFeature() != null) ? getFeature().getVersionedIdentifier().toString() : ""; //$NON-NLS-1$
+ currentReference = new JarContentReference(archiveID, getURL());
+ currentReference = asLocalReference(currentReference, monitor);
+ references[0] = currentReference;
+ } catch (IOException e) {
+ references[0] = continueOnErrorOrRethrow(archiveID, e);
+ }
+ return references;
+ }
+
+ /*
+ * @see IFeatureContentProvider#getPluginEntryArchiveReferences(IPluginEntry)
+ */
+ public ContentReference[] getPluginEntryArchiveReferences(IPluginEntry pluginEntry, InstallMonitor monitor) throws CoreException {
+
+ // 1 plugin <-> 1 jar
+ // we return the JAR file
+ ContentReference[] references = new ContentReference[1];
+ String archiveID = getPathID(pluginEntry);
+ ISite site = (getFeature() == null) ? null : getFeature().getSite();
+ ISiteContentProvider siteContentProvider = (site == null) ? null : site.getSiteContentProvider();
+ URL url = (siteContentProvider == null) ? null : siteContentProvider.getArchiveReference(archiveID);
+
+ try {
+ references[0] = retrieveLocalJar(new JarContentReference(archiveID, url), monitor);
+ } catch (IOException e) {
+ references[0] = continueOnErrorOrRethrow(archiveID, e);
+ }
+ return references;
+ }
+
+ private ContentReference retrieveLocalJar(JarContentReference reference, InstallMonitor monitor) throws IOException, CoreException {
+ //If the site does not support pack200, just get the jar as normal
+ if(siteModel == null || !siteModel.supportsPack200() || !JarProcessor.canPerformUnpack()) {
+ ContentReference contentReference = null;
+ try {
+ contentReference = asLocalReference(reference, monitor);
+ }
+ catch (FileNotFoundException e) {
+ contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e);
+ }
+ catch (IOException e) {
+ contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e);
+ }
+ catch (CoreException e) {
+ contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e);
+ }
+ return contentReference;
+ }
+
+ ContentReference packedRef = null;
+ String key = reference.toString();
+ Object jarLock = LockManager.getLock(key);
+ synchronized (jarLock) {
+ //do we have this jar already?
+ File localFile = Utilities.lookupLocalFile(key);
+ if (localFile != null) {
+ // check if the cached file is still valid (no newer version on server)
+ if (UpdateManagerUtils.isSameTimestamp(reference.asURL(), localFile.lastModified())) {
+ LockManager.returnLock(key);
+ return reference.createContentReference(reference.getIdentifier(), localFile);
+ }
+ }
+
+ try {
+ //don't have jar, check for pack.gz
+ URL packGZURL = new URL(reference.asURL().toExternalForm() + ".pack.gz"); //$NON-NLS-1$
+ packedRef = asLocalReference(new JarContentReference(reference.getIdentifier(), packGZURL), monitor);
+ } catch (IOException e) {
+ //no pack.gz
+ } catch (CoreException e){
+ //no pack.gz
+ }
+ }
+
+ if (packedRef == null) {
+ //no pack.gz on server, get normal jar
+ ContentReference contentReference = null;
+ try {
+ contentReference = asLocalReference(reference, monitor);
+ }
+ catch (FileNotFoundException e) {
+ contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e);
+ }
+ catch (IOException e) {
+ contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e);
+ }
+ catch (CoreException e) {
+ contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e);
+ }
+ return contentReference;
+ }
+
+ boolean success = false;
+ synchronized (jarLock) {
+ String packed = packedRef.toString();
+ Object packedLock = LockManager.getLock(packed);
+ synchronized (packedLock) {
+ try {
+ File tempFile = packedRef.asFile();
+ long timeStamp = tempFile.lastModified();
+
+ JarProcessor processor = JarProcessor.getUnpackProcessor(null);
+ processor.setWorkingDirectory(tempFile.getParent());
+
+ File packedFile = new File(tempFile.toString() + Utils.PACKED_SUFFIX);
+ tempFile.renameTo(packedFile);
+
+ if (monitor != null) {
+ monitor.saveState();
+ monitor.subTask(Messages.JarContentReference_Unpacking + " " + reference.getIdentifier() + Utils.PACKED_SUFFIX); //$NON-NLS-1$
+ monitor.showCopyDetails(false);
+ }
+ //unpacking the jar will strip the ".pack.gz" and leave us back with the original filename
+ try {
+ processor.processJar(packedFile);
+ } catch (Throwable e) {
+ //something is wrong unpacking
+ }
+
+ if(tempFile.exists() && tempFile.length() > 0){
+ success = true;
+ tempFile.setLastModified(timeStamp);
+ Utilities.mapLocalFile(key, tempFile);
+ UpdateCore.getPlugin().getUpdateSession().markVisited(reference.asURL());
+ }
+ } finally {
+ LockManager.returnLock(packed);
+ LockManager.returnLock(key);
+ if(monitor != null)
+ monitor.restoreState();
+ }
+ }
+ }
+ if(!success){
+ //Something went wrong with the unpack, get the normal jar.
+ ContentReference contentReference = null;
+ try {
+ contentReference = asLocalReference(reference, monitor);
+ }
+ catch (FileNotFoundException e) {
+ contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e);
+ }
+ catch (IOException e) {
+ contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e);
+ }
+ catch (CoreException e) {
+ contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e);
+ }
+ return contentReference;
+ }
+ return packedRef;
+ }
+
+ /*
+ * @see IFeatureContentProvider#getNonPluginEntryArchiveReferences(INonPluginEntry)
+ */
+ public ContentReference[] getNonPluginEntryArchiveReferences(INonPluginEntry nonPluginEntry, InstallMonitor monitor) throws CoreException {
+
+ // archive = feature/<id>_<ver>/<file>
+ String archiveID = Site.DEFAULT_FEATURE_PATH + ((getFeature() != null) ? getFeature().getVersionedIdentifier().toString() : ""); //$NON-NLS-1$
+ archiveID += "/" + nonPluginEntry.getIdentifier(); //$NON-NLS-1$
+
+ ContentReference[] references = new ContentReference[1];
+ ContentReference currentReference = null;
+
+ try {
+ ISite site = (getFeature() == null) ? null : getFeature().getSite();
+ ISiteContentProvider siteContentProvider = (site == null) ? null : site.getSiteContentProvider();
+ URL url = (siteContentProvider == null) ? null : siteContentProvider.getArchiveReference(archiveID);
+
+ currentReference = new ContentReference(nonPluginEntry.getIdentifier(), url);
+ currentReference = asLocalReference(currentReference, monitor);
+ references[0] = currentReference;
+
+ } catch (IOException e) {
+ references[0] = continueOnErrorOrRethrow(archiveID, e);
+ }
+
+ return references;
+ }
+
+
+ /*
+ * @see IFeatureContentProvider#getFeatureEntryContentReferences()
+ */
+ public ContentReference[] getFeatureEntryContentReferences(InstallMonitor monitor) throws CoreException {
+
+ return localFeatureFiles; // return cached feature references
+ // Note: assumes this content provider is always called first to
+ // get the feature manifest. This forces the feature files
+ // to be unpacked and caches the references
+ }
+
+ /*
+ * @see IFeatureContentProvider#getPluginEntryContentReferences(IPluginEntry)
+ */
+ public ContentReference[] getPluginEntryContentReferences(IPluginEntry pluginEntry, InstallMonitor monitor) throws CoreException {
+
+ ContentReference[] references = getPluginEntryArchiveReferences(pluginEntry, monitor);
+ ContentReference[] pluginReferences = new ContentReference[0];
+
+ try {
+ if (references[0] instanceof JarContentReference) {
+ JarContentReference localRef = (JarContentReference) asLocalReference(references[0], monitor);
+ pluginReferences = localRef.peek(null, monitor);
+ } else {
+ // return the list of all subdirectories
+ List files = getFiles(references[0].asFile());
+ pluginReferences = new ContentReference[files.size()];
+ for (int i = 0; i < pluginReferences.length; i++) {
+ File currentFile = (File) files.get(i);
+ pluginReferences[i] = new ContentReference(null, currentFile.toURL());
+ }
+ }
+
+ //[20866] we did not preserve executable bit
+ validatePermissions(pluginReferences);
+
+ } catch (IOException e) {
+ throw errorRetrieving(pluginEntry.getVersionedIdentifier().toString(), references[0], e);
+ }
+ return pluginReferences;
+ }
+
+ /*
+ * return all the files under the directory
+ */
+ private List getFiles(File dir) throws IOException {
+ List result = new ArrayList();
+
+ if (!dir.isDirectory())
+ throw new IOException(NLS.bind(Messages.FeaturePackagedContentProvider_InvalidDirectory, (new String[] { dir.getPath() })));
+
+ File[] files = dir.listFiles();
+ if (files != null) // be careful since it can be null
+ for (int i = 0; i < files.length; ++i) {
+ if (files[i].isDirectory()) {
+ result.addAll(getFiles(files[i]));
+ } else {
+ result.add(files[i]);
+ }
+ }
+ return result;
+ }
+
+ /*
+ *
+ */
+ private CoreException errorRetrieving(String obj, ContentReference archive, Exception e) {
+
+ String[] values = new String[] { obj };
+
+ return Utilities.newCoreException(NLS.bind(Messages.FeaturePackagedContentProvider_ErrorRetrieving, values), e);
+
+ }
+
+
+ public void setContinueOnError(boolean continueOnError) {
+ this.continueOnError = continueOnError;
+ }
+
+ /**
+ * This method is used for when a core exception is detected, so, if its decided to rethrow, then
+ * a core exception odes not have to be recreated.
+ *
+ * @param archiveID id of the archive file
+ * @param CoreException
+ * @return NullReference if its decided not to continue
+ * @throws CoreException
+ */
+ /*private ContentReference continueOrErrorOrRethrow(String archiveID, CoreException coreException) throws CoreException {
+ ContentReference reference = null;
+
+ if (continueOnError) {
+ // this ContentReference without a file or URL is purely a
+ // "missing jar" reference.
+ reference = new NullContentReference(archiveID);
+
+ String msg = " ContinueOnError: The following ID was not found, so was skipped, and is not on miror site: " + archiveID; //$NON-NLS-1$
+ String id = UpdateCore.getPlugin().getBundle().getSymbolicName();
+ IStatus status = new Status(IStatus.WARNING, id , 0, msg, null);
+ UpdateCore.log(status);
+
+ }
+ else {
+ throw coreException;
+ }
+ return reference;
+ }*/
+
+ private ContentReference continueOnErrorOrRethrow(String archiveID, Exception e) throws CoreException {
+ ContentReference reference = null;
+
+ if (continueOnError) {
+ // this ContentReference without a file or URL is purely a
+ // "missing jar" reference.
+ reference = new NullContentReference(archiveID);
+
+ String msg = " ContinueOnError: The following ID was not found, so was skipped, and is not on miror site: " + archiveID; //$NON-NLS-1$
+ String id = UpdateCore.getPlugin().getBundle().getSymbolicName();
+ IStatus status = new Status(IStatus.WARNING, id , 0, msg, null);
+ UpdateCore.log(status);
+
+ }
+ else {
+ throw errorRetrieving(archiveID, reference, e);
+ }
+ return reference;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeaturePackagedFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeaturePackagedFactory.java
new file mode 100644
index 0000000..fc55651
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeaturePackagedFactory.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+import java.io.*;
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+import org.eclipse.update.core.model.*;
+
+/**
+ * Factory for Feature Packaged
+ */
+public class FeaturePackagedFactory extends BaseFeatureFactory {
+
+ /*
+ * @see IFeatureFactory#createFeature(URL,ISite,IProgressMonitor)
+ */
+ public IFeature createFeature(URL url,ISite site, IProgressMonitor monitor) throws CoreException {
+ Feature feature = null;
+ InputStream featureStream = null;
+ if (monitor == null)
+ monitor = new NullProgressMonitor();
+ monitor.beginTask(null,2);
+ monitor.worked(1);
+
+
+ try {
+ IFeatureContentProvider contentProvider = new FeaturePackagedContentProvider(url, site);
+ ContentReference manifest = contentProvider.getFeatureManifestReference(null/*IProgressMonitor*/);
+ featureStream = manifest.getInputStream();
+ feature = (Feature)parseFeature(featureStream);
+ monitor.worked(1);
+
+ // if there is no update URL for the Feature
+ // use the Site URL
+ if (feature.getUpdateSiteEntry()==null){
+ URLEntryModel entryModel = createURLEntryModel();
+ URL siteUrl = site.getURL();
+ if (siteUrl!=null){
+ entryModel.setURLString(siteUrl.toExternalForm());
+ entryModel.resolve(siteUrl,null);
+ feature.setUpdateSiteEntryModel(entryModel);
+ }
+ }
+ feature.setFeatureContentProvider(contentProvider);
+ feature.setSite(site);
+ URL baseUrl = null;
+ try {
+ baseUrl = new URL(manifest.asURL(),"."); // make sure we have URL to feature directory //$NON-NLS-1$
+ } catch(MalformedURLException e) {
+ }
+ feature.resolve(baseUrl, baseUrl);
+ feature.markReadOnly();
+ } catch (CoreException e){
+ throw e;
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw Utilities.newCoreException(NLS.bind(Messages.FeatureFactory_CreatingError, (new String[] { url.toExternalForm() })), e);
+ }finally {
+ try {
+ if (featureStream!=null)
+ featureStream.close();
+ } catch (IOException e) {
+ }
+ }
+ return feature;
+ }
+
+ public IncludedFeatureReferenceModel createIncludedFeatureReferenceModel() {
+ return new UpdateSiteIncludedFeatureReference();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeaturePlugin.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeaturePlugin.java
new file mode 100644
index 0000000..f002ed7
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeaturePlugin.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+import org.eclipse.update.core.*;
+/**
+ * An IPluginEntry - IFeature pair.
+ * The IFeature is a featue or a patch wich delivered the plugin
+ */
+public class FeaturePlugin {
+ private IPluginEntry pluginEntry;
+ private IFeature feature;
+ public FeaturePlugin(IPluginEntry entry, IFeature feature) {
+ pluginEntry = entry;
+ this.feature = feature;
+ }
+ public IPluginEntry getEntry() {
+ return pluginEntry;
+ }
+ public IFeature getFeature() {
+ return feature;
+ }
+ /**
+ * Plugins are equal if their IDs and versions are the same.
+ */
+ public boolean equals(Object o) {
+ if (o instanceof FeaturePlugin) {
+ FeaturePlugin p = (FeaturePlugin) o;
+ return getEntry().getVersionedIdentifier().equals(p.getEntry().getVersionedIdentifier());
+ }
+ return false;
+ }
+ public int hashCode() {
+ return getEntry().getVersionedIdentifier().hashCode();
+ }
+ public String toString() {
+ return pluginEntry + " in " + feature; //$NON-NLS-1$
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureTypeFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureTypeFactory.java
new file mode 100644
index 0000000..56aeac4
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeatureTypeFactory.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+
+/**
+ * Manages FeatureFactory extension point
+ */
+public final class FeatureTypeFactory {
+
+ private static FeatureTypeFactory inst;
+ private Map factories;
+
+ private static final String SIMPLE_EXTENSION_ID = "featureTypes"; //$NON-NLS-1$
+
+ /*
+ * hide constructor
+ */
+ private FeatureTypeFactory() {
+ }
+
+ /*
+ * Singleton pattern
+ */
+ public static FeatureTypeFactory getInstance() {
+ if (inst == null)
+ inst = new FeatureTypeFactory();
+ return inst;
+ }
+
+ /*
+ * return the factory for the associated type
+ */
+ public IFeatureFactory getFactory(String type) throws CoreException {
+ //
+ Object instance = getFactories().get(type);
+ if (instance == null) {
+ instance = createFactoryFor(type);
+ getFactories().put(type, instance);
+ }
+ return (IFeatureFactory) instance;
+ }
+
+ /*
+ * creates a factory for the associated type and cache it
+ */
+ private IFeatureFactory createFactoryFor(String type) throws CoreException {
+ IFeatureFactory result = null;
+
+ String pluginID =
+ UpdateCore.getPlugin().getBundle().getSymbolicName();
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IConfigurationElement[] elements =
+ registry.getConfigurationElementsFor(pluginID, SIMPLE_EXTENSION_ID, type);
+
+ if (elements == null || elements.length == 0) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.FeatureTypeFactory_UnableToFindFeatureFactory, (new String[] { type })),
+ null);
+ }
+
+ IConfigurationElement element = elements[0];
+ result = (IFeatureFactory) element.createExecutableExtension("class"); //$NON-NLS-1$
+ return result;
+ }
+
+ /*
+ *
+ */
+ private Map getFactories() {
+ if (factories == null)
+ factories = new HashMap();
+ return factories;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FileFragment.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FileFragment.java
new file mode 100644
index 0000000..309250f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FileFragment.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+
+import java.io.*;
+
+
+public class FileFragment{
+ private File file;
+ private long bytes;
+ public FileFragment(File file, long size){
+ this.file=file;
+ this.bytes=size;
+ }
+ public File getFile(){
+ return file;
+ }
+ public long getSize(){
+ return bytes;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FragmentEntry.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FragmentEntry.java
new file mode 100644
index 0000000..2a7511f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FragmentEntry.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+
+
+/**
+ * This class is used to retrieve the fragments associated with a plugin.
+ */
+public class FragmentEntry {
+
+ private String pluginId;
+ private String pluginVersion;
+ private String name;
+ private String location;
+
+ public FragmentEntry(String id, String version, String name, String location) {
+ this.pluginId = id;
+ this.pluginVersion = version;
+ this.name = name;
+ this.location = location;
+ }
+
+ /**
+ * @return the plugin translatable name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @return the location of the plugin
+ */
+ public String getLocation() {
+ return location;
+ }
+
+ /**
+ * Returns the plug-in identifier for this entry.
+ *
+ * @return the plug-in identifier, or <code>null</code>
+ */
+ public String getPluginIdentifier() {
+ return pluginId;
+ }
+
+ /**
+ * Returns the plug-in version for this entry.
+ *
+ * @return the plug-in version, or <code>null</code>
+ */
+ public String getPluginVersion() {
+ return pluginVersion;
+ }
+
+ /**
+ * @see Object#toString()
+ */
+ public String toString() {
+ String msg = (getPluginIdentifier()!=null)?getPluginIdentifier().toString():""; //$NON-NLS-1$
+ msg += getPluginVersion()!=null?" "+getPluginVersion().toString():""; //$NON-NLS-1$ //$NON-NLS-2$
+ return msg;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ISiteContentConsumer.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ISiteContentConsumer.java
new file mode 100644
index 0000000..ac8ba7d
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ISiteContentConsumer.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+
+ /**
+ * A site content consumer manages the storage or archives, plugins and
+ * feature inside an <code> ISite</code>
+ */
+
+public interface ISiteContentConsumer {
+
+ /**
+ * Stores a content reference into the SiteContentConsumer
+ * @param contentReference the content reference to store
+ * @param monitor the progress monitor
+ * @throws CoreException if an error occurs storing the content reference
+ * @since 2.0
+ */
+ public void store(ContentReference contentReference, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * opens a Non plugin Entry for storage
+ * @return the new FeatureContentConsumer for this <code>INonPluginEntry</code>
+ * @throws CoreException if the opens is done on a FeatureContentConsumer parent other than an IFeature.
+ * @since 2.0
+ */
+ public IContentConsumer open(INonPluginEntry nonPluginEntry) throws CoreException;
+
+ /**
+ * opens a Non plugin Entry for storage
+ * @return the new FeatureContentConsumer for this <code>IPluginEntry</code>
+ * @throws CoreException if the opens is done on a FeatureContentConsumer parent other than an IFeature.
+ * @since 2.0
+ */
+ public IContentConsumer open(IPluginEntry pluginEntry) throws CoreException;
+
+ /**
+ * closes the opened SiteContentConsumer
+ * @throws CoreException
+ * @since 2.0
+ */
+ public IFeatureReference close() throws CoreException ;
+
+
+ /**
+ * aborts the opened SiteContentConsumer
+ * @throws CoreException
+ * @since 2.0
+ */
+ public void abort() throws CoreException;
+
+}
+
+
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallConfiguration.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallConfiguration.java
new file mode 100644
index 0000000..c0801dd
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallConfiguration.java
@@ -0,0 +1,974 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.core;
+
+import org.eclipse.update.internal.model.SiteLocalModel;
+
+import org.eclipse.core.runtime.ListenerList;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.IActivity;
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.configuration.IInstallConfiguration;
+import org.eclipse.update.configuration.IInstallConfigurationChangedListener;
+import org.eclipse.update.configuration.IProblemHandler;
+import org.eclipse.update.configurator.ConfiguratorUtils;
+import org.eclipse.update.configurator.IPlatformConfiguration;
+import org.eclipse.update.core.FeatureContentProvider;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IFeatureReference;
+import org.eclipse.update.core.IPluginEntry;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.ISiteContentProvider;
+import org.eclipse.update.core.ISiteFeatureReference;
+import org.eclipse.update.core.Site;
+import org.eclipse.update.core.SiteManager;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.core.VersionedIdentifier;
+import org.eclipse.update.core.model.SiteModel;
+import org.eclipse.update.internal.configurator.ConfigurationActivator;
+import org.eclipse.update.internal.configurator.FeatureEntry;
+import org.eclipse.update.internal.configurator.PlatformConfiguration;
+import org.eclipse.update.internal.configurator.PluginEntry;
+import org.eclipse.update.internal.configurator.SiteEntry;
+import org.eclipse.update.internal.model.ConfigurationActivityModel;
+import org.eclipse.update.internal.model.ConfiguredSiteModel;
+import org.eclipse.update.internal.model.InstallConfigurationModel;
+import org.osgi.framework.Bundle;
+
+/**
+ * Manages ConfiguredSites
+ *
+ */
+
+public class InstallConfiguration extends InstallConfigurationModel implements IInstallConfiguration {
+ private static boolean isWindows = System.getProperty("os.name").startsWith("Win"); //$NON-NLS-1$ //$NON-NLS-2$
+ private ListenerList listeners = new ListenerList(ListenerList.IDENTITY);
+
+ /*
+ * default constructor.
+ */
+ public InstallConfiguration() {
+ }
+
+ /*
+ * Copy constructor
+ * @since 3.0
+ */
+ public InstallConfiguration(IInstallConfiguration config) throws MalformedURLException, CoreException {
+ this(config, null, null);
+ }
+
+ /*
+ * copy constructor
+ */
+ public InstallConfiguration(IInstallConfiguration config, URL newLocation, String label) throws CoreException, MalformedURLException {
+ // set current date and timeline as caller can call setDate if the
+ // date on the URL string has to be the same
+ Date now = new Date();
+ setCreationDate(now);
+ setCurrent(false);
+
+ if (newLocation == null) {
+ String newFileName = UpdateManagerUtils.getLocalRandomIdentifier(SiteLocalModel.CONFIG_FILE, now);
+ newLocation = UpdateManagerUtils.getURL(((LocalSite)SiteManager.getLocalSite()).getLocationURL(), newFileName, null);
+ }
+ setLocationURLString(newLocation.toExternalForm());
+
+ if (label == null)
+ label = Utilities.format(now);
+ setLabel(label);
+
+ // do not copy list of listeners nor activities
+ // make a copy of the siteConfiguration object
+ if (config != null) {
+ IConfiguredSite[] csites = config.getConfiguredSites();
+ if (csites != null) {
+ for (int i = 0; i < csites.length; i++) {
+ ConfiguredSite configSite = new ConfiguredSite(csites[i]);
+ addConfigurationSiteModel(configSite);
+ }
+ }
+ }
+
+ resolve(newLocation, null);
+ // no need to parse file, all data are initialized
+ initialized = true;
+ }
+
+
+ /*
+ * Returns the list of configured sites or an empty array
+ */
+ public IConfiguredSite[] getConfiguredSites() {
+ ConfiguredSiteModel[] result = getConfigurationSitesModel();
+ if (result.length == 0)
+ return new IConfiguredSite[0];
+ else
+ return (IConfiguredSite[]) result;
+ }
+
+ /*
+ * Returns the default site policy
+ */
+ private int getDefaultPolicy() {
+ return PlatformConfiguration.getDefaultPolicy();
+ }
+
+ /**
+ * Creates a Configuration Site and a new Site
+ * The policy is from <code> org.eclipse.core.boot.IPlatformConfiguration</code>
+ */
+ public IConfiguredSite createConfiguredSite(File file) throws CoreException {
+
+ if (!file.getName().equals("eclipse")) { //$NON-NLS-1$
+ file = new File(file, "eclipse"); //$NON-NLS-1$
+ file.mkdirs();
+ }
+
+ if (isDuplicateSite(file))
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallConfiguration_location_exists, (new String[] { file.getPath() })),null);
+ ISite site = InternalSiteManager.createSite(file);
+
+ //create a config site around the site
+ // even if the site == null
+ BaseSiteLocalFactory factory = new BaseSiteLocalFactory();
+ ConfiguredSite configSite = (ConfiguredSite) factory.createConfigurationSiteModel((SiteModel) site, getDefaultPolicy());
+
+ if (configSite.isNativelyLinked()) {
+ throw Utilities.newCoreException(Messages.InstallConfiguration_AlreadyNativelyLinked, null);
+ }
+
+ if (configSite.isProductSite()) {
+ throw Utilities.newCoreException(Messages.InstallConfiguration_AlreadyProductSite, null);
+ }
+
+ if (site != null) {
+ configSite.setPlatformURLString(site.getURL().toExternalForm());
+
+ // obtain the list of plugins
+ IPlatformConfiguration runtimeConfiguration = ConfiguratorUtils.getCurrentPlatformConfiguration();
+ ConfigurationPolicy configurationPolicy = configSite.getConfigurationPolicy();
+ String[] pluginPath = new String[0];
+ if (configurationPolicy.getPolicy() == IPlatformConfiguration.ISitePolicy.USER_INCLUDE)
+ pluginPath = configurationPolicy.getPluginPath(site);
+
+ // create new Site in configuration
+ IPlatformConfiguration.ISitePolicy sitePolicy = runtimeConfiguration.createSitePolicy(configurationPolicy.getPolicy(), pluginPath);
+
+ // change runtime
+ IPlatformConfiguration.ISiteEntry siteEntry = runtimeConfiguration.createSiteEntry(site.getURL(), sitePolicy);
+ runtimeConfiguration.configureSite(siteEntry);
+
+ // if the privatre marker doesn't already exist create it
+ configSite.createPrivateSiteMarker();
+ ((SiteModel)site).setConfiguredSiteModel(configSite);
+ }
+ // configure all features as enable
+ configure(configSite);
+
+ return configSite;
+ }
+
+ /**
+ * Creates a Configuration Site and a new Site as a private link site
+ * The policy is from <code> org.eclipse.core.boot.IPlatformConfiguration</code>
+ */
+ public IConfiguredSite createLinkedConfiguredSite(File file) throws CoreException {
+ return createConfiguredSite(file);
+// if (isDuplicateSite(file))
+// throw Utilities.newCoreException(UpdateUtils.getFormattedMessage("InstallConfiguration.location.exists", file.getPath()),null);
+//
+// ISite site = InternalSiteManager.createSite(file);
+//
+// //create a config site around the site
+// // even if the site == null
+// BaseSiteLocalFactory factory = new BaseSiteLocalFactory();
+// ConfiguredSite configSite = (ConfiguredSite) factory.createConfigurationSiteModel((SiteModel) site, getDefaultPolicy());
+//
+// if (!configSite.isExtensionSite()) {
+// String msg = Policy.bind("InstallConfiguration.NotAnExtensionSite");
+// throw Utilities.newCoreException(msg, null);
+// }
+//
+// if (configSite.isNativelyLinked()) {
+// throw Utilities.newCoreException("InstallConfiguration.AlreadyNativelyLinked", null);
+// }
+//
+// if (site != null) {
+// configSite.setPlatformURLString(site.getURL().toExternalForm());
+//
+// // obtain the list of plugins
+// IPlatformConfiguration runtimeConfiguration = ConfiguratorUtils.getCurrentPlatformConfiguration();
+// ConfigurationPolicy configurationPolicy = configSite.getConfigurationPolicy();
+// String[] pluginPath = new String[0];
+// if (configurationPolicy.getPolicy() == IPlatformConfiguration.ISitePolicy.USER_INCLUDE)
+// pluginPath = configurationPolicy.getPluginPath(site);
+//
+// // create new Site in configuration
+// IPlatformConfiguration.ISitePolicy sitePolicy = runtimeConfiguration.createSitePolicy(configurationPolicy.getPolicy(), pluginPath);
+//
+// // change runtime
+// IPlatformConfiguration.ISiteEntry siteEntry = runtimeConfiguration.createSiteEntry(site.getURL(), sitePolicy);
+// runtimeConfiguration.configureSite(siteEntry);
+//
+// }
+//
+// // configure all features as enable
+// configure(configSite);
+//
+// return configSite;
+ }
+
+ /*
+ *Configure all features as Enable Check we only enable highest version
+ */
+ private void configure(ConfiguredSite linkedSite) throws CoreException {
+ ISite site = linkedSite.getSite();
+ ISiteFeatureReference[] newFeaturesRef = site.getFeatureReferences();
+
+ for (int i = 0; i < newFeaturesRef.length; i++) {
+ // TRACE
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) {
+ String reconciliationType = "enable (optimistic)"; //$NON-NLS-1$
+ UpdateCore.debug("New Linked Site:New Feature: " + newFeaturesRef[i].getURL() + " as " + reconciliationType); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ ConfigurationPolicy policy = linkedSite.getConfigurationPolicy();
+ policy.configure(newFeaturesRef[i], true, false);
+ }
+ SiteReconciler.checkConfiguredFeatures(linkedSite);
+ }
+
+ /*
+ *
+ */
+ public void addConfiguredSite(IConfiguredSite site) {
+ if (!isCurrent() && isReadOnly())
+ return;
+
+ ConfigurationActivity activity = new ConfigurationActivity(IActivity.ACTION_SITE_INSTALL);
+ activity.setLabel(site.getSite().getURL().toExternalForm());
+ activity.setDate(new Date());
+ ConfiguredSiteModel configSiteModel = (ConfiguredSiteModel) site;
+ addConfigurationSiteModel(configSiteModel);
+ configSiteModel.setInstallConfigurationModel(this);
+
+ // notify listeners
+ Object[] configurationListeners = listeners.getListeners();
+ for (int i = 0; i < configurationListeners.length; i++) {
+ IInstallConfigurationChangedListener listener = ((IInstallConfigurationChangedListener) configurationListeners[i]);
+ listener.installSiteAdded(site);
+ }
+
+ // everything done ok
+ activity.setStatus(IActivity.STATUS_OK);
+ this.addActivity(activity);
+ }
+
+ /**
+ * Method addActivity.
+ * @param activity
+ */
+ public void addActivity(IActivity activity) {
+ addActivityModel((ConfigurationActivityModel)activity);
+ }
+
+ /*
+ *
+ */
+ public void removeConfiguredSite(IConfiguredSite site) {
+ if (!isCurrent() && isReadOnly())
+ return;
+
+ if (removeConfigurationSiteModel((ConfiguredSiteModel) site)) {
+ // notify listeners
+ Object[] configurationListeners = listeners.getListeners();
+ for (int i = 0; i < configurationListeners.length; i++) {
+ IInstallConfigurationChangedListener listener = ((IInstallConfigurationChangedListener) configurationListeners[i]);
+ listener.installSiteRemoved(site);
+ }
+
+ //activity
+ ConfigurationActivity activity = new ConfigurationActivity(IActivity.ACTION_SITE_REMOVE);
+ activity.setLabel(site.getSite().getURL().toExternalForm());
+ activity.setDate(new Date());
+ activity.setStatus(IActivity.STATUS_OK);
+ this.addActivity(activity);
+ }
+ }
+
+ /*
+ * @see IInstallConfiguration#addInstallConfigurationChangedListener(IInstallConfigurationChangedListener)
+ */
+ public void addInstallConfigurationChangedListener(IInstallConfigurationChangedListener listener) {
+ listeners.add(listener);
+ }
+
+ /*
+ * @see IInstallConfiguration#removeInstallConfigurationChangedListener(IInstallConfigurationChangedListener)
+ */
+ public void removeInstallConfigurationChangedListener(IInstallConfigurationChangedListener listener) {
+ listeners.remove(listener);
+ }
+
+
+ /*
+ * Deletes the configuration from its URL/location
+ */
+ public void remove() {
+ // save the configuration
+ if ("file".equalsIgnoreCase(getURL().getProtocol())) { //$NON-NLS-1$
+ // the location points to a file
+ File file = new File(getURL().getFile());
+ UpdateManagerUtils.removeFromFileSystem(file);
+ }
+ }
+
+ /**
+ * Saves the configuration into its URL/location
+ * and changes the platform configuration.
+ * The runtime site entries from platform.xml are updated as required
+ * (cannot recreate these because must preserve other runtime state) [18520]
+ * @return true if restart is needed
+ */
+ public boolean save() throws CoreException {
+
+ // Write info into platform for the next runtime
+ IPlatformConfiguration runtimeConfiguration = ConfiguratorUtils.getCurrentPlatformConfiguration();
+ ConfiguredSiteModel[] configurationSites = getConfigurationSitesModel();
+
+ // clean configured Entries from platform runtime
+ IPlatformConfiguration.IFeatureEntry[] configuredFeatureEntries = runtimeConfiguration.getConfiguredFeatureEntries();
+ for (int i = 0; i < configuredFeatureEntries.length; i++) {
+ runtimeConfiguration.unconfigureFeatureEntry(configuredFeatureEntries[i]);
+ }
+
+ // [19958] remember sites currently configured by runtime (use
+ // temp configuration object rather than a straight list to ensure
+ // correct lookup)
+ IPlatformConfiguration tempConfig = null;
+ try {
+ tempConfig = ConfiguratorUtils.getPlatformConfiguration(null);
+ IPlatformConfiguration.ISiteEntry[] tmpSites = runtimeConfiguration.getConfiguredSites();
+ for (int i = 0; i < tmpSites.length; i++) {
+ tempConfig.configureSite(tmpSites[i]);
+ }
+ } catch (IOException e) {
+ // assume no currently configured sites
+ }
+
+ //check sites
+ checkSites(configurationSites, runtimeConfiguration);
+
+ // Save the plugin path, primary feature and platform
+ for (int i = 0; i < configurationSites.length; i++) {
+ ConfiguredSite cSite = ((ConfiguredSite) configurationSites[i]);
+ ConfigurationPolicy configurationPolicy = cSite.getConfigurationPolicy();
+
+ savePluginPath(cSite, runtimeConfiguration, tempConfig);
+
+ // IF primary feature URL or platform feature URL that we need to pass to runtime config
+ // is part of platform:base:, write it as platform:base: URL
+ IFeatureReference[] configuredFeaturesRef = configurationPolicy.getConfiguredFeatures();
+ for (int j = 0; j < configuredFeaturesRef.length; j++) {
+ IFeature feature = null;
+ try {
+ feature = configuredFeaturesRef[j].getFeature(null);
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ }
+ saveFeatureEntry(cSite, feature, runtimeConfiguration);
+ }
+ }
+
+ // [19958] remove any extra site entries from runtime configuration
+ // (site entries that no longer exist in this configuration)
+ if (tempConfig != null) {
+ IPlatformConfiguration.ISiteEntry[] tmpSites = tempConfig.getConfiguredSites();
+ for (int i = 0; i < tmpSites.length; i++) {
+ runtimeConfiguration.unconfigureSite(tmpSites[i]);
+ }
+ }
+
+ try {
+ runtimeConfiguration.save();
+ // log configuration and activities
+ this.date = new Date(runtimeConfiguration.getChangeStamp());
+ if ("file".equalsIgnoreCase(getURL().getProtocol())) //$NON-NLS-1$
+ UpdateCore.log(this);
+ resetActivities();
+ return isRestartNeeded(runtimeConfiguration);
+ } catch (IOException e) {
+ CoreException exc = Utilities.newCoreException(NLS.bind(Messages.InstallConfiguration_UnableToSavePlatformConfiguration, (new String[] { runtimeConfiguration.getConfigurationLocation().toExternalForm() })), e);
+ UpdateCore.warn("",exc); //$NON-NLS-1$
+ }
+ return true;
+ }
+
+ /*
+ * Write the plugin path for each site
+ * Do not check if the site already existed before [16696].
+ * Reuse any runtime site objects in platform.cfg (to preserve state) [18520].
+ */
+ private void savePluginPath(ConfiguredSite cSite, IPlatformConfiguration runtimeConfiguration, IPlatformConfiguration tempConfig) // [19958]
+ throws CoreException {
+
+ ConfigurationPolicy configurationPolicy = cSite.getConfigurationPolicy();
+
+ // create a ISitePolicy (policy, pluginPath)
+ // for the site
+ String[] pluginPath = configurationPolicy.getPluginPath(cSite.getSite());
+ IPlatformConfiguration.ISitePolicy sitePolicy = runtimeConfiguration.createSitePolicy(configurationPolicy.getPolicy(), pluginPath);
+
+ // get the URL of the site that matches the one platform.cfg gave us
+ URL urlToCheck = null;
+ try {
+ urlToCheck = new URL(cSite.getPlatformURLString());
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallConfiguration_UnableToCreateURL, (new String[] { cSite.getPlatformURLString() })), e);
+ } catch (ClassCastException e) {
+ throw Utilities.newCoreException(Messages.InstallConfiguration_UnableToCast, e);
+ }
+
+ // update runtime configuration [18520]
+ // Note: we must not blindly replace the site entries because they
+ // contain additional runtime state that needs to be preserved.
+ IPlatformConfiguration.ISiteEntry siteEntry = runtimeConfiguration.findConfiguredSite(urlToCheck);
+ if (siteEntry == null)
+ siteEntry = runtimeConfiguration.createSiteEntry(urlToCheck, sitePolicy);
+ else {
+ siteEntry.setSitePolicy(sitePolicy);
+ ((SiteEntry)siteEntry).refreshPlugins();
+ if (tempConfig != null) // [19958] remove reused entries from list
+ tempConfig.unconfigureSite(siteEntry);
+ }
+ ((SiteEntry)siteEntry).setEnabled(cSite.isEnabled());
+ runtimeConfiguration.configureSite(siteEntry, true /*replace if exists*/);
+ }
+
+ /*
+ * Save the Feature entry
+ * The feature can be a primary feature and/or a platform feature
+ */
+ private void saveFeatureEntry(ConfiguredSite cSite, IFeature feature, IPlatformConfiguration runtimeConfiguration) throws CoreException {
+ if (feature == null)
+ return;
+
+ // get the URL of the plugin that corresponds to the feature (pluginid = featureid)
+ String id = feature.getVersionedIdentifier().getIdentifier();
+ IPluginEntry[] entries = feature.getPluginEntries();
+ URL url = null;
+ IPluginEntry featurePlugin = null;
+ for (int k = 0; k < entries.length; k++) {
+ if (id.equalsIgnoreCase(entries[k].getVersionedIdentifier().getIdentifier())) {
+ url = getRuntimeConfigurationURL(entries[k], cSite);
+ featurePlugin = entries[k];
+ break;
+ }
+ }
+ String pluginVersion = null;
+ if (featurePlugin != null)
+ pluginVersion = featurePlugin.getVersionedIdentifier().getVersion().toString();
+
+ // Find the site
+ SiteEntry siteEntry = null;
+ try {
+ URL featureUrl = new URL(cSite.getPlatformURLString());
+ siteEntry = (SiteEntry)runtimeConfiguration.findConfiguredSite(featureUrl);
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallConfiguration_UnableToCreateURL, (new String[] { cSite.getPlatformURLString() })), e);
+ } catch (ClassCastException e) {
+ throw Utilities.newCoreException(Messages.InstallConfiguration_UnableToCast, e);
+ }
+
+ // if the URL doesn't exist throw a CoreException
+ if (siteEntry == null) {
+ throw new CoreException(
+ new Status(IStatus.ERROR, UpdateCore.getPlugin().getBundle().getSymbolicName(),
+ NLS.bind(Messages.InstallConfiguration_unableToFindSite, (new String[] { cSite.getSite().getURL().toExternalForm(), runtimeConfiguration.getConfigurationLocation().toExternalForm() }))));
+ }
+
+ // write the primary features
+ if (feature.isPrimary()) {
+ // get any fragments for the feature plugin
+ ArrayList list = new ArrayList();
+ if (url != null)
+ list.add(url);
+ if (featurePlugin != null) {
+ URL[] fragments = getRuntimeFragmentURLs(featurePlugin);
+ list.addAll(Arrays.asList(fragments));
+ }
+ URL[] roots = (URL[]) list.toArray(new URL[0]);
+ String pluginIdentifier = feature.getPrimaryPluginID();
+
+ // save information in runtime platform state
+ String version = feature.getVersionedIdentifier().getVersion().toString();
+ String application = feature.getApplication();
+ FeatureEntry featureEntry = (FeatureEntry)runtimeConfiguration.createFeatureEntry(id, version, pluginIdentifier, pluginVersion, true, application, roots);
+ featureEntry.setURL(getFeatureRelativeURL(feature));
+ siteEntry.addFeatureEntry(featureEntry);
+ } else {
+ // write non-primary feature entries
+ String version = feature.getVersionedIdentifier().getVersion().toString();
+ String pluginIdentifier = feature.getPrimaryPluginID();
+ FeatureEntry featureEntry = (FeatureEntry)runtimeConfiguration.createFeatureEntry(id, version, pluginIdentifier, pluginVersion, false, null, null);
+ featureEntry.setURL(getFeatureRelativeURL(feature));
+ siteEntry.addFeatureEntry(featureEntry);
+ }
+
+ // write the platform features (features that contain special platform plugins)
+ IPluginEntry[] platformPlugins = getPlatformPlugins(feature, runtimeConfiguration);
+ for (int k = 0; k < platformPlugins.length; k++) {
+ id = platformPlugins[k].getVersionedIdentifier().getIdentifier();
+ url = getRuntimeConfigurationURL(platformPlugins[k], cSite);
+ if (url != null) {
+ runtimeConfiguration.setBootstrapPluginLocation(id, url);
+ }
+ }
+ }
+
+ /*
+ * Log if we are about to create a site that didn't exist before
+ * in platform.cfg [16696].
+ */
+ private void checkSites(ConfiguredSiteModel[] configurationSites, IPlatformConfiguration runtimeConfiguration) throws CoreException {
+
+ // check all the sites we are about to write already existed
+ // they should have existed either because they were created by
+ // updateManager or because we read them from platform.cfg
+ for (int i = 0; i < configurationSites.length; i++) {
+ // get the URL of the site that matches the one platform.cfg gave us
+ URL urlToCheck = null;
+ try {
+ urlToCheck = new URL(configurationSites[i].getPlatformURLString());
+ } catch (MalformedURLException e) {
+ UpdateCore.warn(NLS.bind(Messages.InstallConfiguration_UnableToCreateURL, (new String[] { configurationSites[i].getPlatformURLString() })), e);
+ } catch (ClassCastException e) {
+ UpdateCore.warn(Messages.InstallConfiguration_UnableToCast, e);
+ }
+
+ // if the URL doesn't exits log it
+ IPlatformConfiguration.ISiteEntry siteEntry = runtimeConfiguration.findConfiguredSite(urlToCheck);
+ if (siteEntry == null) {
+ UpdateCore.warn(NLS.bind(Messages.InstallConfiguration_unableToFindSite, (new String[] { urlToCheck.toExternalForm(), runtimeConfiguration.getConfigurationLocation().toExternalForm() })));
+ }
+ }
+ }
+
+
+ /*
+ * reverts this configuration to the match the new one
+ *
+ * Compare the oldSites with the currentOne. the old state is the state we want to revert to.
+ *
+ * If a site was in old state, but not in the currentOne, keep it in the hash.
+ * If a site is in the currentOne but was not in the old state, unconfigure all features and add it in the hash
+ * If a site was in baoth state, calculate the 'delta' and re-set it in the hash map
+ *
+ * At the end, set the configured site from the new sites hash map
+ *
+ */
+ public void revertTo(IInstallConfiguration configuration, IProgressMonitor monitor, IProblemHandler handler) throws CoreException, InterruptedException {
+
+ IConfiguredSite[] oldConfigSites = configuration.getConfiguredSites();
+ IConfiguredSite[] nowConfigSites = this.getConfiguredSites();
+
+ // create a hashtable of the *old* and *new* sites
+ Map oldSitesMap = new Hashtable(0);
+ Map newSitesMap = new Hashtable(0);
+ for (int i = 0; i < oldConfigSites.length; i++) {
+ IConfiguredSite element = oldConfigSites[i];
+ oldSitesMap.put(element.getSite().getURL().toExternalForm(), element);
+ newSitesMap.put(element.getSite().getURL().toExternalForm(), element);
+ }
+ // create list of all the sites that map the *old* sites
+ // we want the intersection between the old sites and the current sites
+ if (nowConfigSites != null) {
+ String key = null;
+
+ for (int i = 0; i < nowConfigSites.length; i++) {
+ key = nowConfigSites[i].getSite().getURL().toExternalForm();
+ IConfiguredSite oldSite = (IConfiguredSite) oldSitesMap.get(key);
+ if (oldSite != null) {
+ // the Site existed before, calculate the delta between its current state and the
+ // state we are reverting to and put it back into the map
+ ((ConfiguredSite) nowConfigSites[i]).revertTo(oldSite, monitor, handler);
+ } else {
+ // the site didn't exist in the InstallConfiguration we are reverting to
+ // unconfigure everything from this site so it is still present
+ ISiteFeatureReference[] featuresToUnconfigure = nowConfigSites[i].getSite().getFeatureReferences();
+ for (int j = 0; j < featuresToUnconfigure.length; j++) {
+ IFeature featureToUnconfigure = null;
+ try {
+ featureToUnconfigure = featuresToUnconfigure[j].getFeature(null);
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ }
+ if (featureToUnconfigure != null)
+ nowConfigSites[i].unconfigure(featureToUnconfigure);
+ }
+ }
+ newSitesMap.put(key,nowConfigSites[i]);
+ }
+
+ // the new configuration has the exact same sites as the old configuration
+ // the old configuration in the Map are either as-is because they don't exist
+ // in the current one, or they are the delta from the current one to the old one
+ Collection sites = newSitesMap.values();
+ if (sites != null && !sites.isEmpty()) {
+ ConfiguredSiteModel[] sitesModel = new ConfiguredSiteModel[sites.size()];
+ sites.toArray(sitesModel);
+ setConfigurationSiteModel(sitesModel);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallConfiguration#getActivities()
+ */
+ public IActivity[] getActivities() {
+ if (getActivityModel().length == 0)
+ return new IActivity[0];
+ return (IActivity[]) getActivityModel();
+ }
+
+ /*
+ * returns the list of platform plugins of the feature or an empty list
+ * if the feature doesn't contain any platform plugins
+ */
+ private IPluginEntry[] getPlatformPlugins(IFeature feature, IPlatformConfiguration runtimeConfiguration) {
+ Map featurePlatformPlugins = new HashMap();
+ String[] platformPluginID = runtimeConfiguration.getBootstrapPluginIdentifiers();
+ IPluginEntry[] featurePlugins = feature.getPluginEntries();
+
+ for (int i = 0; i < platformPluginID.length; i++) {
+ String featurePluginId = null;
+ for (int j = 0; j < featurePlugins.length; j++) {
+ featurePluginId = featurePlugins[j].getVersionedIdentifier().getIdentifier();
+ if (platformPluginID[i].equals(featurePluginId)) {
+ featurePlatformPlugins.put(platformPluginID[i], featurePlugins[j]);
+ }
+ }
+ }
+
+ Collection values = featurePlatformPlugins.values();
+ if (values == null || values.size() == 0)
+ return new IPluginEntry[0];
+
+ IPluginEntry[] result = new IPluginEntry[values.size()];
+ Iterator iter = values.iterator();
+ int index = 0;
+ while (iter.hasNext()) {
+ result[index] = ((IPluginEntry) iter.next());
+ index++;
+ }
+ return result;
+ }
+
+ /*
+ * returns the URL of the pluginEntry on the site
+ * Transform the URL to use platform: protocol if needed
+ * return null if the URL to write is not valid
+ */
+ private URL getRuntimeConfigurationURL(IPluginEntry entry, ConfiguredSite cSite) throws CoreException {
+
+ String rootString = cSite.getPlatformURLString();
+ String pluginPathID = getPathID(entry);
+ try {
+ ISiteContentProvider siteContentProvider = cSite.getSite().getSiteContentProvider();
+ URL pluginEntryfullURL = siteContentProvider.getArchiveReference(pluginPathID);
+
+ //
+ if (!rootString.startsWith("platform")) { //$NON-NLS-1$
+ // DEBUG:
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION)
+ UpdateCore.debug("getRuntimeConfiguration Plugin Entry Full URL:" + pluginEntryfullURL + " Platform String:" + rootString + " [NON PLATFORM URL]."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ return pluginEntryfullURL;
+ }
+
+ //URL pluginEntryRootURL = Platform.resolve(new URL(rootString));
+ // Do not resolve [16507], just use platform:base/ as a root
+ // rootString = platform:base
+ // pluginRoot = /home/a
+ // pluginFull = /home/a/c/boot.jar
+ // relative = platform:/base/c/boot.jar
+ URL pluginEntryRootURL = cSite.getSite().getURL();
+ String relativeString = UpdateManagerUtils.getURLAsString(pluginEntryRootURL, pluginEntryfullURL);
+ URL result = new URL(new URL(rootString), relativeString);
+
+ // DEBUG:
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION)
+ UpdateCore.debug("getRuntimeConfiguration plugin Entry Full URL:" + pluginEntryfullURL + " Platform String:" + rootString + " Site URL:" + pluginEntryRootURL + " Relative:" + relativeString); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+
+ // verify we are about to write a valid file URL
+ // check with fullURL as it is not resolved to platform:base/
+ if (pluginEntryfullURL != null) {
+ if ("file".equals(pluginEntryfullURL.getProtocol())) { //$NON-NLS-1$
+ String fileString = pluginEntryfullURL.getFile();
+ if (!new File(fileString).exists()) {
+ UpdateCore.warn("The URL:" + result + " doesn't point to a valid platform plugin.The URL will not be written in the platform configuration", new Exception()); //$NON-NLS-1$ //$NON-NLS-2$
+ return null;
+ }
+ }
+ }
+
+ return result;
+ } catch (IOException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallConfiguration_UnableToCreateURL, (new String[] { rootString })), e);
+ }
+ }
+
+ /*
+ * Return URLs for any fragments that are associated with the specified plugin entry
+ */
+ private URL[] getRuntimeFragmentURLs(IPluginEntry entry) throws CoreException {
+
+ // get the identifier associated with the entry
+ VersionedIdentifier vid = entry.getVersionedIdentifier();
+
+ // get the plugin descriptor from the registry
+ Bundle bundle = Platform.getBundle(vid.getIdentifier());
+ ArrayList list = new ArrayList();
+ if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.INSTALLED) {
+ FragmentEntry[] fragments = UpdateManagerUtils.getFragments(bundle);
+ for (int i = 0; fragments != null && i < fragments.length; i++) {
+ String location = fragments[i].getLocation();
+ try {
+ URL locationURL = new URL(location);
+ locationURL = FileLocator.toFileURL(FileLocator.resolve(locationURL));
+ list.add(asInstallRelativeURL(locationURL));
+ } catch (IOException e) {
+ // skip bad fragments
+ }
+ }
+ }
+ return (URL[]) list.toArray(new URL[0]);
+ }
+
+ /**
+ * Returns the path identifier for a plugin entry.
+ * <code>plugins/<pluginId>_<pluginVersion>.jar</code>
+ * @return the path identifier
+ */
+ private String getPathID(IPluginEntry entry) {
+ return Site.DEFAULT_PLUGIN_PATH + entry.getVersionedIdentifier().toString() + FeatureContentProvider.JAR_EXTENSION;
+ }
+
+ /**
+ * Try to recast URL as platform:/base/
+ */
+ private URL asInstallRelativeURL(URL url) {
+ // get location of install
+ URL install = ConfiguratorUtils.getInstallURL();
+
+ // try to determine if supplied URL can be recast as install-relative
+ if (install.getProtocol().equals(url.getProtocol())) {
+ if (install.getProtocol().equals("file")) { //$NON-NLS-1$
+ String installS = new File(install.getFile()).getAbsolutePath().replace(File.separatorChar, '/');
+ if (!installS.endsWith("/")) //$NON-NLS-1$
+ installS += "/"; //$NON-NLS-1$
+ String urlS = new File(url.getFile()).getAbsolutePath().replace(File.separatorChar, '/');
+ if (!urlS.endsWith("/")) //$NON-NLS-1$
+ urlS += "/"; //$NON-NLS-1$
+ int ix = installS.lastIndexOf("/"); //$NON-NLS-1$
+ if (ix != -1) {
+ installS = installS.substring(0, ix + 1);
+ if (urlS.startsWith(installS)) {
+ try {
+ return new URL("platform:/base/" + urlS.substring(installS.length())); //$NON-NLS-1$
+ } catch (MalformedURLException e) {
+ }
+ }
+ }
+ }
+ }
+ return url;
+ }
+
+ private boolean isDuplicateSite(File siteDirectory) {
+ IConfiguredSite[] sites = getConfiguredSites();
+ URL fileURL;
+ try {
+ fileURL = siteDirectory.toURL();
+ } catch (MalformedURLException e) {
+ return false;
+ }
+ for (int i = 0; i < sites.length; i++) {
+ URL url = sites[i].getSite().getURL();
+ if (UpdateManagerUtils.sameURL(fileURL, url))
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ * Returns the feature url relative to the site.
+ */
+ private String getFeatureRelativeURL(IFeature feature) {
+ String url = feature.getURL().toExternalForm();
+ String siteURL = feature.getSite().getURL().toExternalForm();
+ // TODO fix this. toURL() returns file:/d:/eclipse/etc... wheareas the
+ // platform.asLocalURL() returns file:d:/eclipse/etc... (no leading / )
+// if (url.startsWith("file:/") && Platform.getOS().equals("win32"))
+// url = "file:" + url.substring(6);
+
+ if (url.startsWith(siteURL))
+ return url.substring(siteURL.length());
+ else
+ return url;
+ }
+
+ /**
+ * @return true if restart is needed
+ */
+ private boolean isRestartNeeded(IPlatformConfiguration runtimeConfig) {
+
+ // First, create a map for faster lookups
+ Set newPluginsSet = null;
+ if (runtimeConfig instanceof PlatformConfiguration) {
+ newPluginsSet = ((PlatformConfiguration)runtimeConfig).getPluginPaths();
+ // On windows, we will be doing case insensitive search as well, so lower it now
+ if (isWindows) {
+ String[] newPluginsSetArray = (String[])newPluginsSet.toArray( new String[newPluginsSet.size()]);
+ for (int i = 0; i < newPluginsSetArray.length; i++) {
+ newPluginsSet.add(newPluginsSetArray[i].toLowerCase());
+ }
+ }
+ } else {
+ URL[] newBundlePaths = runtimeConfig.getPluginPath();
+ newPluginsSet = new HashSet(newBundlePaths.length);
+ for (int i=0; i<newBundlePaths.length; i++) {
+
+ String pluginLocation = newBundlePaths[i].getFile();
+ newPluginsSet.add(pluginLocation);
+ // On windows, we will be doing case insensitive search as well, so lower it now
+ if (isWindows)
+ newPluginsSet.add(pluginLocation.toLowerCase());
+ }
+ }
+
+
+
+ Bundle[] oldBundles = UpdateCore.getPlugin().getBundleContext().getBundles();
+
+ int offset = ConfigurationActivator.UPDATE_PREFIX.length();
+ for (int i=0; i<oldBundles.length; i++) {
+ if (oldBundles[i].getBundleId() == 0)
+ continue; // skip the system bundle
+ String oldBundleLocation = oldBundles[i].getLocation();
+ // Don't worry about bundles we did not install
+ if (!oldBundleLocation.startsWith(ConfigurationActivator.UPDATE_PREFIX))
+ continue;
+ oldBundleLocation = oldBundleLocation.substring(offset);
+
+ if (newPluginsSet.contains(oldBundleLocation))
+ continue;
+ if (isWindows && newPluginsSet.contains(oldBundleLocation.toLowerCase()))
+ continue;
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION)
+ UpdateCore.debug("Bundle " + oldBundleLocation + " has been removed"); //$NON-NLS-1$ //$NON-NLS-2$
+ return true;
+ }
+
+ if (runtimeConfig instanceof PlatformConfiguration) {
+ return areThereNewVersionOfOldPlugins( ((PlatformConfiguration)runtimeConfig).getPlugins(), oldBundles);
+ }
+
+ return false;
+ }
+
+ /**
+ * The method should only be called if all old plug-ins exist in the new
+ * configuration. Determines if a new version was added to any plugin ID, so
+ * more versions are enabled for any given plug-in id then in old
+ * configuration.
+ *
+ * @param newConfigurationPlugins
+ * @param oldConfigurationBundles
+ * @return
+ */
+ private boolean areThereNewVersionOfOldPlugins(PluginEntry[] newConfigurationPlugins, Bundle[] oldConfigurationBundles) {
+
+
+ for ( int i = 0; i < oldConfigurationBundles.length; i++) {
+ if (oldConfigurationBundles[i].getBundleId() == 0)
+ continue; // skip the system bundle
+ if ( getNumberOfPlugins(oldConfigurationBundles[i].getSymbolicName(), oldConfigurationBundles) != getNumberOfPlugins(oldConfigurationBundles[i].getSymbolicName(), newConfigurationPlugins)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private int getNumberOfPlugins(String symbolicName, PluginEntry[] newConfigurationPlugins) {
+
+ int numberOfPlugins = 0;
+
+ for ( int i = 0; i < newConfigurationPlugins.length; i++) {
+ if ( symbolicName.equals(newConfigurationPlugins[i].getPluginIdentifier())) {
+ numberOfPlugins++;
+ }
+ }
+
+ return numberOfPlugins;
+ }
+
+ private int getNumberOfPlugins(String symbolicName, Bundle[] oldConfigurationBundles) {
+
+ int numberOfPlugins = 0;
+
+ for ( int i = 0; i < oldConfigurationBundles.length; i++) {
+ if ( symbolicName.equals(oldConfigurationBundles[i].getSymbolicName())) {
+ numberOfPlugins++;
+ }
+ }
+
+ return numberOfPlugins;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof InstallConfiguration))
+ return false;
+
+ InstallConfiguration config = (InstallConfiguration)obj;
+
+ return getCreationDate().equals(config.getCreationDate()) &&
+ getLabel().equals(config.getLabel()) &&
+ getLocationURLString().equals(config.getLocationURLString());
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallHandlerProxy.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallHandlerProxy.java
new file mode 100644
index 0000000..0b47f34
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallHandlerProxy.java
@@ -0,0 +1,613 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 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.update.internal.core;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.ContentReference;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IFeatureContentConsumer;
+import org.eclipse.update.core.IInstallHandler;
+import org.eclipse.update.core.IInstallHandlerEntry;
+import org.eclipse.update.core.IInstallHandlerWithFilter;
+import org.eclipse.update.core.INonPluginEntry;
+import org.eclipse.update.core.IPluginEntry;
+import org.eclipse.update.core.IVerificationListener;
+import org.eclipse.update.core.InstallMonitor;
+import org.eclipse.update.core.Utilities;
+import org.osgi.framework.Bundle;
+
+public class InstallHandlerProxy implements IInstallHandlerWithFilter {
+
+ private IFeature feature = null;
+ private int type;
+ private IInstallHandler handler = null;
+ private IStatus savedStatus = null;
+ private boolean DEBUG = false;
+
+ private static final String EXT_PLUGIN = "org.eclipse.update.core"; //$NON-NLS-1$
+ private static final String UI_PLUGIN = "org.eclipse.ui"; //$NON-NLS-1$
+ private static final String EXT_POINT = "installHandlers"; //$NON-NLS-1$
+ private Method nonPluginDataAcceptor = null;
+
+ /**
+ * A class loader that combines a the org.eclipse.update.core plugin class loader with the
+ * org.eclipse.ui class loader (only when UI is active).
+ */
+ private static class InstallHandlerClassLoader extends URLClassLoader {
+ private Bundle updateCore;
+ private Bundle eclipseUI;
+
+ public InstallHandlerClassLoader(URL[] classpath) {
+ super(classpath);
+ updateCore = Platform.getBundle(EXT_PLUGIN);
+ eclipseUI = Platform.getBundle(UI_PLUGIN);
+ if (eclipseUI != null && eclipseUI.getState() != Bundle.ACTIVE)
+ eclipseUI = null;
+ }
+
+ public Class loadClass(String className) throws ClassNotFoundException {
+ // First check update core plugin loader, then the eclipse ui plugin loader
+ Class c = null;
+ try {
+ c = updateCore.loadClass(className);
+ } catch (ClassNotFoundException e) {
+ try {
+ if(eclipseUI != null)
+ c = eclipseUI.loadClass(className);
+ } catch (ClassNotFoundException e2) {
+ } finally {
+ }
+ } finally {
+ }
+ if (c != null)
+ return c;
+ else
+ return super.loadClass(className);
+ }
+
+ public URL getResource(String resName) {
+ // First check update core plugin loader, then the eclipse ui plugin loader
+ URL u = updateCore.getResource(resName);
+ if(u == null && eclipseUI != null)
+ u = eclipseUI.getResource(resName);
+
+ if (u != null)
+ return u;
+ else
+ return super.getResource(resName);
+ }
+ }
+
+ public InstallHandlerProxy(
+ int type,
+ IFeature feature,
+ IInstallHandlerEntry entry,
+ InstallMonitor monitor)
+ throws CoreException {
+
+ initialize(type, feature, entry, monitor);
+ }
+
+ /*
+ * @see IInstallHandler#initialize
+ */
+ public void initialize(
+ int type,
+ IFeature feature,
+ IInstallHandlerEntry entry,
+ InstallMonitor monitor)
+ throws CoreException {
+
+ DEBUG = UpdateCore.DEBUG_SHOW_IHANDLER;
+ // validate arguments
+ if (feature == null)
+ throw new IllegalArgumentException();
+ this.feature = feature;
+ this.type = type;
+
+ // check if we have a handler entry specified in the feature.xml
+ if (entry == null) {
+ if (DEBUG)
+ debug("not specified"); //$NON-NLS-1$
+ return; // no handler entry
+ }
+
+ String library = entry.getLibrary();
+ String handlerName = entry.getHandlerName();
+ if (handlerName == null || handlerName.trim().equals("")) { //$NON-NLS-1$
+ if (DEBUG)
+ debug("not specified"); //$NON-NLS-1$
+ return; // no handler class spacified in entry
+ }
+ if (DEBUG) {
+ debug("handler=" + handlerName); //$NON-NLS-1$
+ debug("path= " + library); //$NON-NLS-1$
+ }
+
+ // get handler instance
+ try {
+ if (library == null || library.trim().equals("")) //$NON-NLS-1$
+ this.handler = getGlobalHandler(handlerName);
+ else
+ this.handler = getLocalHandler(library, handlerName);
+ if (this.handler == null)
+ return;
+ handler.initialize(type, feature, entry, monitor);
+ } catch (ClassNotFoundException e) {
+ handleExceptionInInit(
+ NLS.bind(Messages.InstallHandler_notFound, (new String[] { feature.getLabel() })),
+ e);
+
+ } catch (ClassCastException e) {
+ handleExceptionInInit(
+ NLS.bind(Messages.InstallHandler_invalidHandler, (new String[] { feature.getLabel() })),
+ e);
+ } catch (CoreException e) {
+ handleExceptionInInit(null, e);
+ } catch (Exception e) {
+ handleExceptionInInit(
+ NLS.bind(Messages.InstallHandler_unableToCreateHandler, (new String[] { feature.getLabel() })),
+ e);
+ }
+
+ }
+
+ /*
+ * @see IInstallHandler#installInitiated
+ */
+ public void installInitiated() throws CoreException {
+ if (handler == null)
+ return;
+ else {
+ try {
+ if (DEBUG)
+ debug("calling installInitiated()"); //$NON-NLS-1$
+ handler.installInitiated();
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallHandler#allPluginsDownloaded
+ */
+ public void pluginsDownloaded(IPluginEntry[] plugins) throws CoreException {
+ if (handler == null)
+ return;
+ else {
+ try {
+ if (DEBUG)
+ debug("calling pluginsDownloaded()"); //$NON-NLS-1$
+ handler.pluginsDownloaded(plugins);
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallHandler#allPluginsInstalled
+ */
+ public void completeInstall(IFeatureContentConsumer consumer)
+ throws CoreException {
+ if (handler == null)
+ return;
+ else {
+ try {
+ if (DEBUG)
+ debug("calling completeInstall()"); //$NON-NLS-1$
+ handler.completeInstall(consumer);
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallHandler#allDataDownloaded
+ */
+ public void nonPluginDataDownloaded(
+ INonPluginEntry[] nonPluginData,
+ IVerificationListener listener)
+ throws CoreException {
+ if (handler == null)
+ return;
+ else {
+ try {
+ if (DEBUG)
+ debug("calling nonPluginDataDownloaded()"); //$NON-NLS-1$
+ handler.nonPluginDataDownloaded(nonPluginData, listener);
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallHandler#installCompleted
+ */
+ public void installCompleted(boolean success) throws CoreException {
+ if (handler == null)
+ return;
+ else {
+ try {
+ if (DEBUG)
+ debug("calling installCompleted()"); //$NON-NLS-1$
+ handler.installCompleted(success);
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallHandler#configureInitiated
+ */
+ public void configureInitiated() throws CoreException {
+ if (handler == null)
+ return;
+ else {
+ try {
+ if (DEBUG)
+ debug("calling configureInitiated()"); //$NON-NLS-1$
+ handler.configureInitiated();
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallHandler#completeConfigure
+ */
+ public void completeConfigure() throws CoreException {
+ if (handler == null)
+ return;
+ else {
+ try {
+ if (DEBUG)
+ debug("calling completeConfigure()"); //$NON-NLS-1$
+ handler.completeConfigure();
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallHandler#configureCompleted
+ */
+ public void configureCompleted(boolean success) throws CoreException {
+ if (handler == null)
+ return;
+ else {
+ try {
+ if (DEBUG)
+ debug("calling configureCompleted()"); //$NON-NLS-1$
+ handler.configureCompleted(success);
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallHandler#unconfigureInitiated
+ */
+ public void unconfigureInitiated() throws CoreException {
+ if (handler == null)
+ return;
+ else {
+ try {
+ if (DEBUG)
+ debug("calling unconfigureInitiated()"); //$NON-NLS-1$
+ handler.unconfigureInitiated();
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallHandler#completeUnconfigure
+ */
+ public void completeUnconfigure() throws CoreException {
+ if (handler == null)
+ return;
+ else {
+ try {
+ if (DEBUG)
+ debug("calling completeUnconfigure()"); //$NON-NLS-1$
+ handler.completeUnconfigure();
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallHandler#unconfigureCompleted
+ */
+ public void unconfigureCompleted(boolean success) throws CoreException {
+ if (handler == null) {
+ if (savedStatus == null)
+ return;
+ else
+ throw new CoreException(savedStatus); // delayed exception
+ } else {
+ try {
+ if (DEBUG)
+ debug("calling unconfigureCompleted()"); //$NON-NLS-1$
+ handler.unconfigureCompleted(success);
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ if (savedStatus != null)
+ throw new CoreException(savedStatus); // delayed exception
+ }
+ }
+
+ /*
+ * @see IInstallHandler#uninstallInitiated
+ */
+ public void uninstallInitiated() throws CoreException {
+ if (handler == null)
+ return;
+ else {
+ try {
+ if (DEBUG)
+ debug("calling uninstallInitiated()"); //$NON-NLS-1$
+ handler.uninstallInitiated();
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallHandler#completeUninstall
+ */
+ public void completeUninstall() throws CoreException {
+ if (handler == null)
+ return;
+ else {
+ try {
+ if (DEBUG)
+ debug("calling completeUninstall()"); //$NON-NLS-1$
+ handler.completeUninstall();
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ }
+ }
+
+ /*
+ * @see IInstallHandler#uninstallCompleted
+ */
+ public void uninstallCompleted(boolean success) throws CoreException {
+ if (handler == null) {
+ if (savedStatus == null)
+ return;
+ else
+ throw new CoreException(savedStatus); // delayed exception
+ } else {
+ try {
+ if (DEBUG)
+ debug("calling uninstallCompleted()"); //$NON-NLS-1$
+ handler.uninstallCompleted(success);
+ } catch (Throwable e) {
+ handleExceptionInCall(e, feature);
+ }
+ if (savedStatus != null)
+ throw new CoreException(savedStatus); // delayed exception
+ }
+ }
+
+ /*
+ * common exception handling for initialization
+ */
+ private void handleExceptionInInit(String s, Exception e)
+ throws CoreException {
+
+ CoreException ce;
+ if (e instanceof CoreException)
+ ce = (CoreException) e;
+ else
+ ce = Utilities.newCoreException(s, e);
+
+ if (isUndoAction()) {
+ // for "undo" operations, deactivate handler and log error
+ String id =
+ UpdateCore.getPlugin().getBundle().getSymbolicName();
+ IStatus status =
+ new Status(IStatus.ERROR, id, 0, "InstallHandler.deactivated", ce); //$NON-NLS-1$
+ UpdateCore.getPlugin().getLog().log(status);
+ handler = null; // disable subsequent handler calls
+ savedStatus = status;
+ } else
+ // for "do" operations, hurl ...
+ throw ce;
+ }
+
+ /*
+ * common exception handling for calls to install handler
+ */
+ private void handleExceptionInCall(Throwable e, IFeature feature)
+ throws CoreException {
+
+ CoreException ce;
+ if (e instanceof CoreException)
+ ce = (CoreException) e;
+ else
+ ce =
+ Utilities.newCoreException(
+ NLS.bind(Messages.InstallHandler_callException, (new String[] { feature.getLabel() })),
+ e);
+
+ if (isUndoAction()) {
+ // for "undo" operations, deactivate handler and log error
+ String id =
+ UpdateCore.getPlugin().getBundle().getSymbolicName();
+ IStatus status =
+ new Status(IStatus.ERROR, id, 0, "InstallHandler.deactivated", ce); //$NON-NLS-1$
+ UpdateCore.getPlugin().getLog().log(status);
+ handler = null; // disable subsequent handler calls
+ savedStatus = status;
+ } else
+ // for "do" operations, hurl ...
+ throw ce;
+ }
+
+ /*
+ * Indicates whether we are doing (install, configure) or
+ * undoing (uninstall, unconfigure)
+ */
+ private boolean isUndoAction() {
+ if (this.type == IInstallHandler.HANDLER_ACTION_INSTALL
+ || this.type == IInstallHandler.HANDLER_ACTION_CONFIGURE)
+ return false; // causes exception to be thrown and action aborted
+ else
+ return true; // causes exception to be logged and action continues
+ }
+
+ /*
+ * get an instance of handler downloaded as part of the feature
+ */
+ private IInstallHandler getLocalHandler(String libs, String name)
+ throws IOException, CoreException, ClassNotFoundException, InstantiationException, IllegalAccessException {
+
+ // Get baseline URL for handler (relative to feature.xml). For
+ // features being installed from a server (eg. http protocol)
+ // the URL will most likely be to a local file copy containing the
+ // unpacked feature jar.
+ ContentReference baseRef =
+ feature.getFeatureContentProvider().getFeatureManifestReference(null);
+ URL base = null;
+ if (baseRef != null)
+ base = baseRef.asURL();
+ if (base == null)
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.InstallHandler_unableToCreateHandler, (new String[] { this.feature.getLabel() })),
+ null);
+
+
+ // determine loader class path
+ StringTokenizer libraries = new StringTokenizer(libs, ","); //$NON-NLS-1$
+ URL[] cp = new URL[libraries.countTokens()];
+ for( int token = 0; token < cp.length; token++) {
+ cp[token] = new URL(base, libraries.nextToken());
+ }
+ if (this.type == IInstallHandler.HANDLER_ACTION_UNINSTALL) {
+ // check if we are doing uninstall
+ // ... need to make temp copy of library (being removed)
+ URL[] jars = new URL[cp.length];
+ for( int jar = 0; jar < cp.length; jar++) {
+ File tempLib = File.createTempFile("tmp" + jar, ".jar"); //$NON-NLS-1$ //$NON-NLS-2$
+ tempLib.deleteOnExit();
+ FileOutputStream fos = null;
+ InputStream is = null;
+ try {
+ fos = new FileOutputStream(tempLib);
+ is = new FileInputStream(cp[jar].getPath());
+ Utilities.copy(is, fos, null);
+ } finally {
+ if (fos != null)
+ try {
+ fos.close();
+ } catch (Exception e) {
+ }
+ if (is != null)
+ try {
+ is.close();
+ } catch (Exception e) {
+ }
+ }
+ jars[jar] = tempLib.toURL();
+ }
+ cp = jars;
+ }
+
+ // create class loader, load and instantiate handler
+ ClassLoader loader = new InstallHandlerClassLoader(cp);
+ Class clazz = loader.loadClass(name);
+ IInstallHandler handler = (IInstallHandler) clazz.newInstance();
+ return handler;
+ }
+
+ /*
+ * get instance of global handler registered via extension point
+ */
+ private IInstallHandler getGlobalHandler(String name) throws Exception {
+
+ IExtensionRegistry reg = Platform.getExtensionRegistry();
+ IConfigurationElement[] handlerExtension =
+ reg.getConfigurationElementsFor(EXT_PLUGIN, EXT_POINT, name);
+ if (handlerExtension == null || handlerExtension.length <= 0)
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.InstallHandler_unableToCreateHandler, (new String[] { this.feature.getLabel() })),
+ null);
+
+ return (IInstallHandler) handlerExtension[0].createExecutableExtension("class"); //$NON-NLS-1$
+ }
+
+ private void debug(String s) {
+ String pfx = (feature==null) ? "" : feature.getVersionedIdentifier().toString(); //$NON-NLS-1$
+ System.out.println("InstallHandler["+pfx+"]: " + s); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ public boolean acceptNonPluginData(INonPluginEntry data) {
+ Boolean result = new Boolean(true);
+ if (handler != null){
+ if (DEBUG)
+ debug("calling acceptNonPluginData()"); //$NON-NLS-1$
+ if(handler instanceof IInstallHandlerWithFilter)
+ return ((IInstallHandlerWithFilter)handler).acceptNonPluginData(data);
+ else{ //support upgrade from legacy versions
+ if(getNonPluginDataAcceptor() != null){
+ try{
+ Object[] param = {data};
+ result = (Boolean)getNonPluginDataAcceptor().invoke(handler,param);
+ }catch(Exception e){
+ //todo
+ }
+ }
+ }
+ }
+ return result.booleanValue();
+ }
+ private Method getNonPluginDataAcceptor(){
+ if(nonPluginDataAcceptor == null){
+ try{
+ Class[] types = {INonPluginEntry.class};
+ nonPluginDataAcceptor = handler.getClass().getMethod("acceptNonPluginData",types); //$NON-NLS-1$
+ }catch(NoSuchMethodException nsme){
+ }
+ }
+ return nonPluginDataAcceptor;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallLogParser.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallLogParser.java
new file mode 100644
index 0000000..495d38c
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallLogParser.java
@@ -0,0 +1,245 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+import java.io.*;
+import java.net.*;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.configurator.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.operations.*;
+
+
+/**
+ * Parses the installation log and creates installation configuration objects
+ */
+public class InstallLogParser {
+ private IPath logPath;
+ private BufferedReader buffRead;
+ private InstallConfiguration currentConfiguration;
+ private HashMap installConfigMap;
+ private Comparator comparator;
+
+ private static final String FEATURE_INSTALL = "feature-install"; //$NON-NLS-1$
+ private static final String FEATURE_REMOVE = "feature-remove"; //$NON-NLS-1$
+ private static final String SITE_INSTALL = "site-install"; //$NON-NLS-1$
+ private static final String SITE_REMOVE = "site-remove"; //$NON-NLS-1$
+ private static final String UNCONFIGURE = "feature-disable"; //$NON-NLS-1$
+ private static final String CONFIGURE = "feature-enable"; //$NON-NLS-1$
+ private static final String REVERT = "revert"; //$NON-NLS-1$
+ private static final String RECONCILIATION = "reconciliation"; //$NON-NLS-1$
+ private static final String PRESERVED = "preserve-configuration"; //$NON-NLS-1$
+
+ private static final String ACTIVITY = "!ACTIVITY"; //$NON-NLS-1$
+
+ public static final String SUCCESS = "success"; //$NON-NLS-1$
+ public static final String FAILURE = "failure"; //$NON-NLS-1$
+
+
+ public InstallLogParser(){
+ String loc = ConfiguratorUtils.getCurrentPlatformConfiguration().getConfigurationLocation().getFile();
+ logPath = new Path(loc).removeLastSegments(1).append("install.log"); //$NON-NLS-1$
+ installConfigMap = new HashMap();
+ try {
+ InstallConfiguration[] configs = (InstallConfiguration[])SiteManager.getLocalSite().getConfigurationHistory();
+ for (int i=0;i<configs.length; i++){
+ if (!configs[i].isCurrent())
+ installConfigMap.put(new Long(configs[i].getCreationDate().getTime()), configs[i]);
+ }
+ // Need to make a copy of the current config instead
+ InstallConfiguration config = getConfigCopy((InstallConfiguration)SiteManager.getLocalSite().getCurrentConfiguration());
+ installConfigMap.put(new Long(config.getCreationDate().getTime()), config);
+
+ } catch (CoreException e) {
+ UpdateCore.log(e);
+ } catch (MalformedURLException e){
+ UpdateCore.log(e);
+ }
+ comparator = new Comparator(){
+ public int compare(Object e1, Object e2) {
+ Date date1 = ((InstallConfiguration)e1).getCreationDate();
+ Date date2 = ((InstallConfiguration)e2).getCreationDate();
+ return date1.before(date2) ? 1 : -1;
+ }
+ };
+ }
+ private InstallConfiguration getConfigCopy(InstallConfiguration origConfig) throws CoreException, MalformedURLException{
+ InstallConfiguration config = new InstallConfiguration(origConfig, origConfig.getURL(), origConfig.getLabel() );
+ config.setCreationDate(origConfig.getCreationDate());
+ return config;
+ }
+ public void parseInstallationLog(){
+ try {
+ openLog();
+ parseLog();
+ } catch (CoreException e) {
+ UpdateUtils.logException(e);
+ } finally {
+ closeLog();
+ }
+ }
+
+ private void openLog() throws CoreException {
+ try {
+ // throws FileNotFoundException, IOException
+ InputStream is = new FileInputStream(logPath.toOSString());
+ // throws UnsupportedEncodingException
+ InputStreamReader isr = new InputStreamReader(is,"UTF-8"); //$NON-NLS-1$
+ buffRead = new BufferedReader(isr);
+ } catch (Exception e) {
+ throwCoreException(e);
+ }
+ }
+
+ private void throwCoreException(Throwable e) throws CoreException {
+ throw new CoreException(
+ new Status(
+ IStatus.ERROR,
+ UpdateUtils.getPluginId(),
+ IStatus.ERROR,
+ Messages.InstallLogParser_errors,
+ e));
+ }
+
+ private void parseLog() throws CoreException {
+ // .install-log template
+ // !CONFIGURATION <configuration-date>
+ // !ACTIVITY <date> <target> <action> <status>
+
+ try {
+ String type, status, action;
+ StringTokenizer htmlCode;
+
+ while (buffRead.ready()) {
+
+ htmlCode = new StringTokenizer(buffRead.readLine());
+ while (!(htmlCode.hasMoreElements())) {
+ if (!buffRead.ready())
+ return;
+ htmlCode = new StringTokenizer(buffRead.readLine());
+ }
+
+ type = htmlCode.nextToken().trim();
+
+ if (type.equals(ACTIVITY)) {
+ String time = htmlCode.nextToken();
+ String date;
+ StringBuffer target = new StringBuffer();
+ date = htmlCode.nextToken("."); //$NON-NLS-1$
+ htmlCode.nextToken(" "); //$NON-NLS-1$
+ while (htmlCode.countTokens() > 2){
+ target.append(" "); //$NON-NLS-1$
+ target.append(htmlCode.nextToken());
+ }
+
+ action = htmlCode.nextToken();
+ status = htmlCode.nextToken();
+ createActivity(action, time, date, status, target.toString(), currentConfiguration);
+ } else {
+ String time = htmlCode.nextToken();
+ StringBuffer date;
+ date = new StringBuffer();
+ while (htmlCode.countTokens() > 0){
+ if (date.length() != 0)
+ date.append(" "); //$NON-NLS-1$
+ date.append(htmlCode.nextToken());
+ }
+ currentConfiguration = (InstallConfiguration)installConfigMap.get(new Long(time));
+ }
+ }
+ } catch (Exception e) {
+ throwCoreException(e);
+ }
+ }
+
+ private void closeLog() {
+ try {
+ if (buffRead != null)
+ buffRead.close();
+ } catch (IOException e) {
+ } finally {
+ buffRead = null;
+ }
+ }
+ private IActivity createActivity(String action, String time, String date, String status, String target, InstallConfiguration config){
+ ConfigurationActivity a = new ConfigurationActivity();
+
+ int code = 0;
+ if (FEATURE_INSTALL.equals(action))
+ code = IActivity.ACTION_FEATURE_INSTALL;
+ else if (FEATURE_REMOVE.equals(action))
+ code = IActivity.ACTION_FEATURE_REMOVE;
+ else if (SITE_INSTALL.equals(action))
+ code = IActivity.ACTION_SITE_INSTALL;
+ else if (SITE_REMOVE.equals(action))
+ code = IActivity.ACTION_SITE_REMOVE;
+ else if (UNCONFIGURE.equals(action))
+ code = IActivity.ACTION_UNCONFIGURE;
+ else if (CONFIGURE.equals(action))
+ code = IActivity.ACTION_CONFIGURE;
+ else if (REVERT.equals(action))
+ code = IActivity.ACTION_REVERT;
+ else if (RECONCILIATION.equals(action))
+ code = IActivity.ACTION_RECONCILIATION;
+ else if (PRESERVED.equals(action))
+ code = IActivity.ACTION_ADD_PRESERVED;
+
+ a.setAction(code);
+ try {
+ long activityTime = Long.parseLong(time);
+ a.setDate(new Date(activityTime));
+ } catch (NumberFormatException e) {
+ //PAL foundation
+ //a.setDate(new Date(date));
+ try {
+ a.setDate(new SimpleDateFormat().parse(date));
+ } catch (ParseException e1) {
+ //ignore
+ }
+ }
+ a.setStatus(SUCCESS.equals(status) ? IActivity.STATUS_OK : IActivity.STATUS_NOK);
+ a.setLabel(target);
+ a.setInstallConfigurationModel(config);
+
+ if (config != null && !configContainsActivity(config, a)){
+ config.addActivity(a);
+ }
+
+ return a;
+ }
+
+ private boolean configContainsActivity(InstallConfiguration c, IActivity a){
+ IActivity[] activities = c.getActivities();
+ for (int i = 0 ; i<activities.length; i++){
+ if (a.equals(activities[i]))
+ return true;
+ }
+ return false;
+ }
+
+ public InstallConfiguration[] getConfigurations(){
+ Collection configSet = installConfigMap.values();
+ InstallConfiguration[] configs = (InstallConfiguration[]) configSet.toArray(new InstallConfiguration[configSet.size()]);
+ Arrays.sort(configs, comparator);
+ return configs;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallRegistry.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallRegistry.java
new file mode 100644
index 0000000..94e73e9
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InstallRegistry.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.Properties;
+
+import org.eclipse.update.configurator.*;
+import org.eclipse.update.core.*;
+
+/**
+ * Keeps track of all the features and plugins installed by Update mgr
+ * so they can be uninstalled later.
+ * The info is persisted in the .config/registry file and each entry has a key=key where
+ * for feature this key is feature_<id>_<version> and for plugins
+ * key is plugin_<id>_<version>. Normally, getVersionedIdentifier() will
+ * return <id>_<version>. Eg: feature_org.eclipse.platform_3.0.0
+ *
+ */
+public class InstallRegistry extends Properties {
+
+ private static final long serialVersionUID = 1L;
+ private File file = null;
+ private final static String REGISTRY = "registry"; //$NON-NLS-1$
+ private static InstallRegistry instance;
+
+ // plugins installed in this eclipse session
+ private HashMap justInstalledPlugins = new HashMap();
+
+ /**
+ * Creates empty Properties.
+ */
+ private InstallRegistry() {
+ super();
+ String configFile =
+ ConfiguratorUtils
+ .getCurrentPlatformConfiguration()
+ .getConfigurationLocation()
+ .getFile();
+ file = new File(configFile);
+ file = file.getParentFile();
+ file = new File(file, REGISTRY);
+ restore();
+ }
+
+ /**
+ * Singleton
+ */
+ public static InstallRegistry getInstance() {
+ if (instance == null)
+ instance = new InstallRegistry();
+ return instance;
+ }
+
+ /**
+ * Restores contents of the Properties from a file.
+ * @return true if persistant data was read in
+ */
+ public boolean restore() {
+ InputStream in = null;
+ boolean loaded = false;
+ clear();
+ // Test if we have a contribution file to start with
+ // If this is a clean start, then we will not have a
+ // contribution file. return false.
+ if (!file.exists())
+ return loaded;
+ try {
+ in = new FileInputStream(file);
+ super.load(in);
+ loaded = true;
+ } catch (IOException e) {
+ UpdateCore.log(e);
+ } finally {
+ if (in != null)
+ try {
+ in.close();
+ } catch (IOException e) {
+ }
+ }
+ return loaded;
+ }
+ /**
+ * Saves contents of the table to a file.
+ * @return true if operation was successful
+ */
+ public synchronized boolean save() {
+ OutputStream out = null;
+ boolean ret = false;
+ try {
+ out = new FileOutputStream(file);
+ super.store(out, "This is a generated file; do not edit."); //$NON-NLS-1$
+ ret = true;
+ } catch (IOException e) {
+ UpdateCore.log(e);
+ } finally {
+ try {
+ if (out != null) {
+ out.close();
+ }
+ } catch (IOException e) {
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Registers an installed feature so it can be uninstalled later.
+ * @param feature feature to register.
+ */
+ public static synchronized void registerFeature(IFeature feature) {
+ String name = "feature_"+feature.getVersionedIdentifier(); //$NON-NLS-1$
+ if (InstallRegistry.getInstance().get(name) == null) {
+ InstallRegistry.getInstance().put(name, name);
+ // we save after each registration
+ InstallRegistry.getInstance().save();
+ }
+ }
+
+ /**
+ * Registers an installed feature so it can be uninstalled later.
+ * @param pluginEntry plugin to register.
+ */
+ public static synchronized void registerPlugin(IPluginEntry pluginEntry) {
+ String name = "plugin_"+pluginEntry.getVersionedIdentifier(); //$NON-NLS-1$
+ if (InstallRegistry.getInstance().get(name) == null) {
+ InstallRegistry.getInstance().put(name, name);
+ // we save after each registration
+ InstallRegistry.getInstance().save();
+ }
+
+ // add plugin to the list of just installed plugins .
+ InstallRegistry.getInstance().justInstalledPlugins.put(name,name);
+ }
+
+ /**
+ * Removes specified feature from registry
+ *
+ */
+ public static synchronized void unregisterFeature(IFeature feature) {
+ String name = "feature_"+feature.getVersionedIdentifier(); //$NON-NLS-1$
+ InstallRegistry.getInstance().remove(name);
+ }
+
+ /**
+ * Removes specified plugin from registry
+ *
+ */
+ public static synchronized void unregisterPlugin(IPluginEntry pluginEntry) {
+ String name = "plugin_"+pluginEntry.getVersionedIdentifier(); //$NON-NLS-1$
+ InstallRegistry.getInstance().remove(name);
+
+ // remove the plugin from the list of just installed plugins (if needed).
+ InstallRegistry.getInstance().justInstalledPlugins.remove(name);
+ }
+
+ /**
+ * Returns true if the plugin was installed during this eclipse session
+ * @param pluginEntry
+ * @return
+ */
+ public boolean isPluginJustInstalled(IPluginEntry pluginEntry) {
+ String name = "plugin_"+pluginEntry.getVersionedIdentifier(); //$NON-NLS-1$
+ return InstallRegistry.getInstance().justInstalledPlugins.get(name) != null;
+ }
+
+ /**
+ * This method is only needed for the update JUnit tests.
+ *
+ */
+ public static void cleanup() {
+ InstallRegistry.getInstance().justInstalledPlugins.clear();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InternalFeatureParser.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InternalFeatureParser.java
new file mode 100644
index 0000000..dd71997
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InternalFeatureParser.java
@@ -0,0 +1,1281 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.core;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.Stack;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.IURLEntry;
+import org.eclipse.update.core.IUpdateConstants;
+import org.eclipse.update.core.model.ContentEntryModel;
+import org.eclipse.update.core.model.FeatureModel;
+import org.eclipse.update.core.model.FeatureModelFactory;
+import org.eclipse.update.core.model.ImportModel;
+import org.eclipse.update.core.model.IncludedFeatureReferenceModel;
+import org.eclipse.update.core.model.InstallHandlerEntryModel;
+import org.eclipse.update.core.model.NonPluginEntryModel;
+import org.eclipse.update.core.model.PluginEntryModel;
+import org.eclipse.update.core.model.URLEntryModel;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Default feature parser.
+ * Parses the feature manifest file as defined by the platform. Defers
+ * to a model factory to create the actual concrete model objects. The
+ * update framework supplies two factory implementations:
+ * <ul>
+ * <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>
+ * <li>@see org.eclipse.update.core.model.FeatureModelFactory
+ * <li>@see org.eclipse.update.core.BaseFeatureFactory
+ * </ul>
+ *
+ * @since 2.0
+ */
+public class InternalFeatureParser extends DefaultHandler {
+
+ private SAXParser parser;
+ private FeatureModelFactory factory;
+ private MultiStatus status;
+
+ private boolean URL_ALREADY_SEEN = false;
+
+ private static final int STATE_IGNORED_ELEMENT = -1;
+ private static final int STATE_INITIAL = 0;
+ private static final int STATE_INCLUDES = 1;
+ private static final int STATE_FEATURE = 2;
+ private static final int STATE_HANDLER = 3;
+ private static final int STATE_DESCRIPTION = 4;
+ private static final int STATE_COPYRIGHT = 5;
+ private static final int STATE_LICENSE = 6;
+ private static final int STATE_URL = 7;
+ private static final int STATE_UPDATE = 8;
+ private static final int STATE_DISCOVERY = 9;
+ private static final int STATE_REQUIRES = 10;
+ private static final int STATE_IMPORT = 11;
+ private static final int STATE_PLUGIN = 12;
+ private static final int STATE_DATA = 13;
+ private static final String PLUGIN_ID = UpdateCore.getPlugin().getBundle().getSymbolicName();
+
+ private static final String FEATURE = "feature"; //$NON-NLS-1$
+ private static final String INCLUDES = "includes"; //$NON-NLS-1$
+ private static final String HANDLER = "install-handler"; //$NON-NLS-1$
+ private static final String DESCRIPTION = "description"; //$NON-NLS-1$
+ private static final String COPYRIGHT = "copyright"; //$NON-NLS-1$
+ private static final String LICENSE = "license"; //$NON-NLS-1$
+ private static final String URL = "url"; //$NON-NLS-1$
+ private static final String UPDATE = "update"; //$NON-NLS-1$
+ private static final String DISCOVERY = "discovery"; //$NON-NLS-1$
+ private static final String REQUIRES = "requires"; //$NON-NLS-1$
+ private static final String IMPORT = "import"; //$NON-NLS-1$
+ private static final String PLUGIN = "plugin"; //$NON-NLS-1$
+ private static final String DATA = "data"; //$NON-NLS-1$
+
+ //debug message
+ private static final String UNSUPPORTED_FILTER_MSG = "Unsupported \"filter\" attribute, ignoring {0}, with id {1}, version {2}";
+
+ // Current State Information
+ Stack stateStack = new Stack();
+
+ // Current object stack (used to hold the current object we are
+ // populating in this plugin descriptor
+ Stack objectStack = new Stack();
+
+ private int currentState;
+ private String location;
+ private boolean ignoredElement = false;
+
+ private final static SAXParserFactory parserFactory =
+ SAXParserFactory.newInstance();
+
+ /**
+ * Constructs a feature parser.
+ *
+ * @since 2.0
+ */
+ public InternalFeatureParser() {
+ super();
+ try {
+ parserFactory.setNamespaceAware(true);
+ this.parser = parserFactory.newSAXParser();
+ } catch (ParserConfigurationException e) {
+ UpdateCore.log(e);
+ } catch (SAXException e) {
+ UpdateCore.log(e);
+ }
+ }
+
+ public void init(FeatureModelFactory factory) {
+ init(factory, null);
+ }
+
+ /**
+ * @param factory
+ * @param location
+ * @since 3.1
+ */
+ public void init(FeatureModelFactory factory, String location) {
+ // PERF: separate instance creation from parsing
+ this.factory = factory;
+ stateStack = new Stack();
+ objectStack = new Stack();
+ status = null;
+ URL_ALREADY_SEEN = false;
+ this.location = location;
+ //parser.reset();
+ }
+
+ public void internalInit(FeatureModelFactory factory, String location) {
+ init(factory, location);
+ stateStack.push(new Integer(STATE_INITIAL));
+ currentState = ((Integer) stateStack.peek()).intValue();
+ }
+
+ public FeatureModel getFeatureModel() throws SAXException {
+ if (objectStack.isEmpty())
+ throw new SAXException(Messages.DefaultFeatureParser_NoFeatureTag);
+ else {
+ if (objectStack.peek() instanceof FeatureModel) {
+ return (FeatureModel) objectStack.pop();
+ } else {
+ String stack = ""; //$NON-NLS-1$
+ Iterator iter = objectStack.iterator();
+ while (iter.hasNext()) {
+ stack = "\r\n" + iter.next().toString() + stack; //$NON-NLS-1$
+ }
+ throw new SAXException(NLS.bind(Messages.DefaultFeatureParser_WrongParsingStack, (new String[] { stack })));
+ }
+ }
+ }
+
+ /**
+ * Parses the specified input steam and constructs a feature model.
+ * The input stream is not closed as part of this operation.
+ *
+ * @param in input stream
+ * @return feature model
+ * @exception SAXException
+ * @exception IOException
+ * @since 2.0
+ */
+ public FeatureModel parse(InputStream in) throws SAXException, IOException {
+ stateStack.push(new Integer(STATE_INITIAL));
+ currentState = ((Integer) stateStack.peek()).intValue();
+ parser.parse(new InputSource(in), this);
+ return getFeatureModel();
+ }
+
+ /**
+ * Returns all status objects accumulated by the parser.
+ *
+ * @return multi-status containing accumulated status, or <code>null</code>.
+ * @since 2.0
+ */
+ public MultiStatus getStatus() {
+ return status;
+ }
+
+ /**
+ * Handle start of element tags
+ * @see DefaultHandler#startElement(String, String, String, Attributes)
+ * @since 2.0
+ */
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("Start Element: uri:" + uri + " local Name:" + localName + " qName:" + qName); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ switch (currentState) {
+ case STATE_IGNORED_ELEMENT :
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultFeatureParser_UnknownElement, (new String[] { localName, getState(currentState) })));
+ break;
+
+ case STATE_INITIAL :
+ handleInitialState(localName, attributes);
+ break;
+
+ case STATE_FEATURE :
+ case STATE_INCLUDES :
+ case STATE_HANDLER :
+ case STATE_DESCRIPTION :
+ case STATE_COPYRIGHT :
+ case STATE_LICENSE :
+ handleFeatureState(localName, attributes);
+ break;
+
+ case STATE_URL :
+ if (URL_ALREADY_SEEN)
+ internalError(Messages.DefaultFeatureParser_TooManyURLtag);
+ handleURLState(localName, attributes);
+ break;
+
+ case STATE_UPDATE :
+ case STATE_DISCOVERY :
+ handleUpdateDiscoveryState(localName, attributes);
+ break;
+
+ case STATE_REQUIRES :
+ handleRequiresState(localName, attributes);
+ break;
+
+ case STATE_IMPORT :
+ handleImportState(localName,attributes);
+ break;
+
+ case STATE_PLUGIN :
+ case STATE_DATA :
+ handleFeatureState(localName, attributes);
+ break;
+
+ default :
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultFeatureParser_UnknownStartState, (new String[] { Integer.toString(currentState) })));
+ break;
+ }
+
+ int newState = ((Integer) stateStack.peek()).intValue();
+ if (newState != STATE_IGNORED_ELEMENT)
+ currentState = newState;
+
+ }
+
+ /**
+ * Handle end of element tags
+ * @see DefaultHandler#endElement(String, String, String)
+ * @since 2.0
+ */
+ public void endElement(String uri, String localName, String qName) {
+
+ // variables used
+ URLEntryModel info = null;
+ FeatureModel featureModel = null;
+ String text = null;
+ int innerState = 0;
+
+ int state = ((Integer) stateStack.peek()).intValue();
+ switch (state) {
+ case STATE_IGNORED_ELEMENT :
+ stateStack.pop();
+ break;
+
+ case STATE_INITIAL :
+ internalError(Messages.DefaultFeatureParser_ParsingStackBackToInitialState);
+ break;
+
+ case STATE_FEATURE :
+ stateStack.pop();
+ if (objectStack.peek() instanceof String) {
+ text = (String) objectStack.pop();
+ FeatureModel feature = (FeatureModel) objectStack.peek();
+ feature.getDescriptionModel().setAnnotation(text);
+ }
+ //do not pop
+ break;
+
+ case STATE_INCLUDES :
+ stateStack.pop();
+ if (objectStack.peek() instanceof IncludedFeatureReferenceModel) {
+ IncludedFeatureReferenceModel includedFeatureRefModel = ((IncludedFeatureReferenceModel) objectStack.pop());
+ if (objectStack.peek() instanceof FeatureModel) {
+ featureModel = (FeatureModel) objectStack.peek();
+ featureModel.addIncludedFeatureReferenceModel(includedFeatureRefModel);
+ }
+ }
+ break;
+
+ case STATE_HANDLER :
+ stateStack.pop();
+ if (objectStack.peek() instanceof InstallHandlerEntryModel) {
+ InstallHandlerEntryModel handlerModel = (InstallHandlerEntryModel) objectStack.pop();
+ featureModel = (FeatureModel) objectStack.peek();
+ if (featureModel.getInstallHandlerModel() != null)
+ internalError(NLS.bind(Messages.DefaultFeatureParser_ElementAlreadySet, (new String[] { getState(state) })));
+ else
+ featureModel.setInstallHandlerModel(handlerModel);
+ }
+ break;
+
+ case STATE_DESCRIPTION :
+ stateStack.pop();
+
+ text = ""; //$NON-NLS-1$
+ while (objectStack.peek() instanceof String) {
+ text = (String) objectStack.pop() + text;
+ }
+ if (objectStack.peek() instanceof URLEntryModel) {
+ info = (URLEntryModel) objectStack.pop();
+ text = cleanupText(text);
+ if (text != null)
+ info.setAnnotation(text);
+
+ innerState = ((Integer) stateStack.peek()).intValue();
+ switch (innerState) {
+ case STATE_FEATURE :
+ if (objectStack.peek() instanceof FeatureModel) {
+ featureModel = (FeatureModel) objectStack.peek();
+ if (featureModel.getDescriptionModel() != null)
+ internalError(NLS.bind(Messages.DefaultFeatureParser_ElementAlreadySet, (new String[] { getState(state) })));
+ else
+ featureModel.setDescriptionModel(info);
+ }
+ break;
+
+ default :
+ internalError(NLS.bind(Messages.DefaultFeatureParser_StateIncludeWrongElement, (new String[] { getState(innerState), getState(state) })));
+ break;
+
+ }
+ }
+ break;
+
+ case STATE_COPYRIGHT :
+ stateStack.pop();
+ text = ""; //$NON-NLS-1$
+ while (objectStack.peek() instanceof String) {
+ text = (String) objectStack.pop() + text;
+ }
+ if (objectStack.peek() instanceof URLEntryModel) {
+ info = (URLEntryModel) objectStack.pop();
+ text = cleanupText(text);
+ if (text != null) {
+ info.setAnnotation(text);
+ }
+
+ innerState = ((Integer) stateStack.peek()).intValue();
+ switch (innerState) {
+ case STATE_FEATURE :
+ if (objectStack.peek() instanceof FeatureModel) {
+ featureModel = (FeatureModel) objectStack.peek();
+ if (featureModel.getCopyrightModel() != null)
+ internalError(NLS.bind(Messages.DefaultFeatureParser_ElementAlreadySet, (new String[] { getState(state) })));
+ else
+ featureModel.setCopyrightModel(info);
+ }
+ break;
+
+ default :
+ internalError(NLS.bind(Messages.DefaultFeatureParser_StateIncludeWrongElement, (new String[] { getState(innerState), getState(state) })));
+ break;
+
+ }
+ }
+ break;
+
+ case STATE_LICENSE :
+ stateStack.pop();
+
+ text = ""; //$NON-NLS-1$
+ while (objectStack.peek() instanceof String) {
+ text = (String) objectStack.pop() + text;
+ }
+ if (objectStack.peek() instanceof URLEntryModel) {
+ info = (URLEntryModel) objectStack.pop();
+ text = cleanupText(text);
+ if (text != null) {
+ info.setAnnotation(text);
+ }
+
+ innerState = ((Integer) stateStack.peek()).intValue();
+ switch (innerState) {
+ case STATE_FEATURE :
+ if (objectStack.peek() instanceof FeatureModel) {
+ featureModel = (FeatureModel) objectStack.peek();
+ if (featureModel.getLicenseModel() != null)
+ internalError(NLS.bind(Messages.DefaultFeatureParser_ElementAlreadySet, (new String[] { getState(state) })));
+ else
+ featureModel.setLicenseModel(info);
+ }
+ break;
+
+ default :
+ internalError(NLS.bind(Messages.DefaultFeatureParser_StateIncludeWrongElement, (new String[] { getState(innerState), getState(state) })));
+ break;
+
+ }
+ }
+ break;
+
+ case STATE_URL :
+ stateStack.pop();
+ URL_ALREADY_SEEN = true;
+ break;
+
+ case STATE_UPDATE :
+ stateStack.pop();
+ if (objectStack.peek() instanceof URLEntryModel) {
+ info = (URLEntryModel) objectStack.pop();
+ if (objectStack.peek() instanceof FeatureModel) {
+ featureModel = (FeatureModel) objectStack.peek();
+ if (featureModel.getUpdateSiteEntryModel() != null) {
+ internalError(NLS.bind(Messages.DefaultFeatureParser_ElementAlreadySet, (new String[] { getState(state) })));
+ } else {
+ featureModel.setUpdateSiteEntryModel(info);
+ }
+ }
+ }
+ break;
+
+ case STATE_DISCOVERY :
+ stateStack.pop();
+ if (objectStack.peek() instanceof URLEntryModel) {
+ info = (URLEntryModel) objectStack.pop();
+ if (objectStack.peek() instanceof FeatureModel) {
+ featureModel = (FeatureModel) objectStack.peek();
+ featureModel.addDiscoverySiteEntryModel(info);
+ }
+ }
+ break;
+
+ case STATE_REQUIRES :
+ stateStack.pop();
+ if (objectStack.peek() instanceof FeatureModel) {
+ boolean foundIgnored = ignoredElement;
+ ignoredElement = false;
+ featureModel = (FeatureModel) objectStack.peek();
+ ImportModel[] importModels = featureModel.getImportModels();
+ if (importModels.length == 0) {
+ if (!foundIgnored) //don't report error if we ignored something
+ internalError(Messages.DefaultFeatureParser_RequireStateWithoutImportElement);
+ } else {
+ boolean patchMode = false;
+ for (int i = 0; i < importModels.length; i++) {
+ ImportModel importModel = importModels[i];
+ if (importModel.isPatch()) {
+ if (patchMode == false)
+ patchMode = true;
+ else {
+ internalError(Messages.DefaultFeatureParser_MultiplePatchImports);
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case STATE_IMPORT :
+ stateStack.pop();
+ if (objectStack.peek() instanceof ImportModel) {
+ ImportModel importModel = (ImportModel) objectStack.pop();
+ if (objectStack.peek() instanceof FeatureModel) {
+ featureModel = (FeatureModel) objectStack.peek();
+ featureModel.addImportModel(importModel);
+ }
+ }
+ break;
+
+ case STATE_PLUGIN :
+ stateStack.pop();
+ if (objectStack.peek() instanceof PluginEntryModel) {
+ PluginEntryModel pluginEntry = (PluginEntryModel) objectStack.pop();
+ if (objectStack.peek() instanceof FeatureModel) {
+ featureModel = (FeatureModel) objectStack.peek();
+ featureModel.addPluginEntryModel(pluginEntry);
+ }
+ }
+ break;
+
+ case STATE_DATA :
+ stateStack.pop();
+ if (objectStack.peek() instanceof NonPluginEntryModel) {
+ NonPluginEntryModel nonPluginEntry = (NonPluginEntryModel) objectStack.pop();
+ if (objectStack.peek() instanceof FeatureModel) {
+ featureModel = (FeatureModel) objectStack.peek();
+ featureModel.addNonPluginEntryModel(nonPluginEntry);
+ }
+ }
+ break;
+
+ default :
+ internalErrorUnknownTag(Messages.DefaultFeatureParser_UnknownEndState + state);
+ break;
+ }
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("End Element:" + uri + ":" + localName + ":" + qName); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ /*
+ * Method cleanupText.
+ * Removes pre white space and post white space
+ * return null if the text only contains whitespaces (\t \r\n and spaces)
+ *
+ * @param text or null
+ * @return String
+ */
+ private String cleanupText(String text) {
+ text = text.trim();
+ if ("".equals(text)) return null; //$NON-NLS-1$
+ return text;
+ }
+
+ /**
+ * Handle character text
+ * @see DefaultHandler#characters(char[], int, int)
+ * @since 2.0
+ */
+ public void characters(char[] ch, int start, int length) {
+ String text = ""; //$NON-NLS-1$
+ boolean valid = true;
+
+ if (valid) {
+ text = new String(ch, start, length);
+ }
+
+ //only push if not unknown state
+ int state = ((Integer) stateStack.peek()).intValue();
+ if (state == STATE_DESCRIPTION || state == STATE_COPYRIGHT || state == STATE_LICENSE)
+ objectStack.push(text);
+
+ }
+
+ /**
+ * Handle errors
+ * @see DefaultHandler#error(SAXParseException)
+ * @since 2.0
+ */
+ public void error(SAXParseException ex) {
+ logStatus(ex);
+ }
+
+ /**
+ * Handle fatal errors
+ * @see DefaultHandler#fatalError(SAXParseException)
+ * @exception SAXException
+ * @since 2.0
+ */
+ public void fatalError(SAXParseException ex) throws SAXException {
+ logStatus(ex);
+ throw ex;
+ }
+
+ private void handleInitialState(String elementName, Attributes attributes) throws SAXException {
+ if (elementName.equals(FEATURE)) {
+ stateStack.push(new Integer(STATE_FEATURE));
+ processFeature(attributes);
+ } else
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultFeatureParser_UnknownElement, (new String[] { elementName, getState(currentState) })));
+ }
+
+ private void handleFeatureState(String elementName, Attributes attributes) throws SAXException {
+ if (elementName.equals(HANDLER)) {
+ stateStack.push(new Integer(STATE_HANDLER));
+ processHandler(attributes);
+ } else if (elementName.equals(DESCRIPTION)) {
+ stateStack.push(new Integer(STATE_DESCRIPTION));
+ processInfo(attributes);
+ } else if (elementName.equals(COPYRIGHT)) {
+ stateStack.push(new Integer(STATE_COPYRIGHT));
+ processInfo(attributes);
+ } else if (elementName.equals(LICENSE)) {
+ stateStack.push(new Integer(STATE_LICENSE));
+ processInfo(attributes);
+ } else if (elementName.equals(URL)) {
+ stateStack.push(new Integer(STATE_URL));
+ //No process as URL tag does not contain any element itself
+ } else if (elementName.equals(INCLUDES)) {
+ stateStack.push(new Integer(STATE_INCLUDES));
+ processIncludes(attributes);
+ } else if (elementName.equals(REQUIRES)) {
+ stateStack.push(new Integer(STATE_REQUIRES));
+ processRequire(attributes);
+ } else if (elementName.equals(PLUGIN)) {
+ stateStack.push(new Integer(STATE_PLUGIN));
+ processPlugin(attributes);
+ } else if (elementName.equals(DATA)) {
+ stateStack.push(new Integer(STATE_DATA));
+ processData(attributes);
+ } else
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultFeatureParser_UnknownElement, (new String[] { elementName, getState(currentState) })));
+ }
+
+ private void handleURLState(String elementName, Attributes attributes) throws SAXException {
+ if (elementName.equals(UPDATE)) {
+ stateStack.push(new Integer(STATE_UPDATE));
+ processURLInfo(attributes);
+ } else if (elementName.equals(DISCOVERY)) {
+ stateStack.push(new Integer(STATE_DISCOVERY));
+ processURLInfo(attributes);
+ } else
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultFeatureParser_UnknownElement, (new String[] { elementName, getState(currentState) })));
+ }
+
+ private void handleRequiresState(String elementName, Attributes attributes) throws SAXException {
+ if (elementName.equals(IMPORT)) {
+ stateStack.push(new Integer(STATE_IMPORT));
+ processImport(attributes);
+ } else
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultFeatureParser_UnknownElement, (new String[] { elementName, getState(currentState) })));
+ }
+ private void handleUpdateDiscoveryState(String elementName, Attributes attributes) throws SAXException {
+ if (elementName.equals(HANDLER)) {
+ stateStack.push(new Integer(STATE_HANDLER));
+ processHandler(attributes);
+ } else if (elementName.equals(DESCRIPTION)) {
+ stateStack.push(new Integer(STATE_DESCRIPTION));
+ processInfo(attributes);
+ } else if (elementName.equals(COPYRIGHT)) {
+ stateStack.push(new Integer(STATE_COPYRIGHT));
+ processInfo(attributes);
+ } else if (elementName.equals(LICENSE)) {
+ stateStack.push(new Integer(STATE_LICENSE));
+ processInfo(attributes);
+ } else if (elementName.equals(URL)) {
+ stateStack.push(new Integer(STATE_URL));
+ //No process as URL tag does not contain any element itself
+ } else if (elementName.equals(INCLUDES)) {
+ stateStack.push(new Integer(STATE_INCLUDES));
+ processIncludes(attributes);
+ } else if (elementName.equals(REQUIRES)) {
+ stateStack.push(new Integer(STATE_REQUIRES));
+ processRequire(attributes);
+ } else if (elementName.equals(PLUGIN)) {
+ stateStack.push(new Integer(STATE_PLUGIN));
+ processPlugin(attributes);
+ } else if (elementName.equals(DATA)) {
+ stateStack.push(new Integer(STATE_DATA));
+ processData(attributes);
+ } else if (elementName.equals(UPDATE)) {
+ stateStack.push(new Integer(STATE_UPDATE));
+ processURLInfo(attributes);
+ } else if (elementName.equals(DISCOVERY)) {
+ stateStack.push(new Integer(STATE_DISCOVERY));
+ processURLInfo(attributes);
+ } else
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultFeatureParser_UnknownElement, (new String[] { elementName, getState(currentState) })));
+ }
+
+
+
+ private void handleImportState(String elementName, Attributes attributes) throws SAXException {
+ if (elementName.equals(HANDLER)) {
+ stateStack.push(new Integer(STATE_HANDLER));
+ processHandler(attributes);
+ } else if (elementName.equals(DESCRIPTION)) {
+ stateStack.push(new Integer(STATE_DESCRIPTION));
+ processInfo(attributes);
+ } else if (elementName.equals(COPYRIGHT)) {
+ stateStack.push(new Integer(STATE_COPYRIGHT));
+ processInfo(attributes);
+ } else if (elementName.equals(LICENSE)) {
+ stateStack.push(new Integer(STATE_LICENSE));
+ processInfo(attributes);
+ } else if (elementName.equals(URL)) {
+ stateStack.push(new Integer(STATE_URL));
+ //No process as URL tag does not contain any element itself
+ } else if (elementName.equals(INCLUDES)) {
+ stateStack.push(new Integer(STATE_INCLUDES));
+ processIncludes(attributes);
+ } else if (elementName.equals(REQUIRES)) {
+ stateStack.push(new Integer(STATE_REQUIRES));
+ processRequire(attributes);
+ } else if (elementName.equals(PLUGIN)) {
+ stateStack.push(new Integer(STATE_PLUGIN));
+ processPlugin(attributes);
+ } else if (elementName.equals(DATA)) {
+ stateStack.push(new Integer(STATE_DATA));
+ processData(attributes);
+ } else if (elementName.equals(IMPORT)) {
+ stateStack.push(new Integer(STATE_IMPORT));
+ processImport(attributes);
+ } else
+ internalErrorUnknownTag(NLS.bind(Messages.DefaultFeatureParser_UnknownElement, (new String[] { elementName, getState(currentState) })));
+ }
+
+ /*
+ * Process feature information
+ */
+ private void processFeature(Attributes attributes) {
+
+ // identifier and version
+ String id = attributes.getValue("id"); //$NON-NLS-1$
+ String ver = attributes.getValue("version"); //$NON-NLS-1$
+
+ if (id == null || id.trim().equals("") //$NON-NLS-1$
+ || ver == null || ver.trim().equals("")) { //$NON-NLS-1$
+ internalError(NLS.bind(Messages.DefaultFeatureParser_IdOrVersionInvalid, (new String[] { id, ver, getState(currentState)})));
+ } else {
+ // create feature model
+ FeatureModel feature = factory.createFeatureModel();
+
+ feature.setFeatureIdentifier(id);
+ feature.setFeatureVersion(ver);
+
+ // label
+ String label = attributes.getValue("label"); //$NON-NLS-1$
+ feature.setLabel(label);
+
+ // provider
+ String provider = attributes.getValue("provider-name"); //$NON-NLS-1$
+ feature.setProvider(provider);
+
+ //image
+ String imageURL = attributes.getValue("image"); //$NON-NLS-1$
+ feature.setImageURLString(imageURL);
+
+ // OS
+ String os = attributes.getValue("os"); //$NON-NLS-1$
+ feature.setOS(os);
+
+ // WS
+ String ws = attributes.getValue("ws"); //$NON-NLS-1$
+ feature.setWS(ws);
+
+ // NL
+ String nl = attributes.getValue("nl"); //$NON-NLS-1$
+ feature.setNL(nl);
+
+ // arch
+ String arch = attributes.getValue("arch"); //$NON-NLS-1$
+ feature.setArch(arch);
+
+ // primary
+ String primary = attributes.getValue("primary"); //$NON-NLS-1$
+ feature.setPrimary(primary != null && primary.trim().equalsIgnoreCase("true")); //$NON-NLS-1$
+
+ // exclusive
+ String exclusive = attributes.getValue("exclusive"); //$NON-NLS-1$
+ feature.setExclusive(exclusive != null && exclusive.trim().equalsIgnoreCase("true")); //$NON-NLS-1$
+
+ // application
+ String application = attributes.getValue("application"); //$NON-NLS-1$
+ feature.setApplication(application);
+
+ // affinity
+ String affinity = attributes.getValue("colocation-affinity"); //$NON-NLS-1$
+ feature.setAffinityFeature(affinity);
+
+ // primary plugin
+ String plugin = attributes.getValue("plugin"); //$NON-NLS-1$
+ feature.setPrimaryPluginID(plugin);
+
+ objectStack.push(feature);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
+ debug("End process DefaultFeature tag: id:" //$NON-NLS-1$
+ +id + " ver:" //$NON-NLS-1$
+ +ver + " label:" //$NON-NLS-1$
+ +label + " provider:" //$NON-NLS-1$
+ +provider);
+ debug("End process DefaultFeature tag: image:" + imageURL); //$NON-NLS-1$
+ debug("End process DefaultFeature tag: ws:" //$NON-NLS-1$
+ +ws + " os:" //$NON-NLS-1$
+ +os + " nl:" //$NON-NLS-1$
+ +nl + " application:" //$NON-NLS-1$
+ +application);
+ }
+ }
+ }
+
+ /*
+ * process URL info with element text
+ */
+ private void processHandler(Attributes attributes) {
+ InstallHandlerEntryModel handler = factory.createInstallHandlerEntryModel();
+
+ String handlerURL = attributes.getValue("url"); //$NON-NLS-1$
+ handler.setURLString(handlerURL);
+
+ String library = attributes.getValue("library"); //$NON-NLS-1$
+ handler.setLibrary(library);
+
+ String clazz = attributes.getValue("handler"); //$NON-NLS-1$
+ handler.setHandlerName(clazz);
+
+ objectStack.push(handler);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("Processed Handler: url:" //$NON-NLS-1$
+ +handlerURL + " library:" //$NON-NLS-1$
+ +library + " class:" //$NON-NLS-1$
+ +clazz);
+ }
+
+ /*
+ * process URL info with element text
+ */
+ private void processInfo(Attributes attributes) {
+ URLEntryModel inf = factory.createURLEntryModel();
+ String infoURL = attributes.getValue("url"); //$NON-NLS-1$
+ inf.setURLString(infoURL);
+
+ objectStack.push(inf);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("Processed Info: url:" + infoURL); //$NON-NLS-1$
+ }
+
+ /*
+ * Process includes information
+ */
+ private void processIncludes(Attributes attributes) {
+
+ // identifier and version
+ String id = attributes.getValue("id"); //$NON-NLS-1$
+ String ver = attributes.getValue("version"); //$NON-NLS-1$
+
+ if (id == null || id.trim().equals("") //$NON-NLS-1$
+ || ver == null || ver.trim().equals("")) { //$NON-NLS-1$
+ internalError(NLS.bind(Messages.DefaultFeatureParser_IdOrVersionInvalid, (new String[] { id, ver, getState(currentState)})));
+ }
+
+ String filter = attributes.getValue("filter");
+ if (filter != null) {
+ //unsupported, ignore this element
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug(NLS.bind(UNSUPPORTED_FILTER_MSG, new String [] {INCLUDES, id, ver}));
+ return;
+ }
+
+ IncludedFeatureReferenceModel includedFeature = factory.createIncludedFeatureReferenceModel();
+ includedFeature.setFeatureIdentifier(id);
+ includedFeature.setFeatureVersion(ver);
+
+ // name
+ String name = attributes.getValue("name");//$NON-NLS-1$
+ includedFeature.setLabel(name);
+
+ // optional
+ String optional = attributes.getValue("optional");//$NON-NLS-1$
+ boolean isOptional = "true".equalsIgnoreCase(optional);//$NON-NLS-1$
+ includedFeature.isOptional(isOptional);
+
+ // search location
+ String locationName = attributes.getValue("search-location");//$NON-NLS-1$
+ // bug 27030
+ if (locationName == null)
+ locationName = attributes.getValue("search_location");//$NON-NLS-1$
+ int searchLocation = IUpdateConstants.SEARCH_ROOT;
+ if ("both".equalsIgnoreCase(locationName))//$NON-NLS-1$
+ searchLocation = IUpdateConstants.SEARCH_ROOT & IUpdateConstants.SEARCH_SELF;
+ if ("self".equalsIgnoreCase(locationName))//$NON-NLS-1$
+ searchLocation = IUpdateConstants.SEARCH_SELF;
+ includedFeature.setSearchLocation(searchLocation);
+
+ // os arch ws nl
+ String os = attributes.getValue("os");//$NON-NLS-1$
+ includedFeature.setOS(os);
+
+ String ws = attributes.getValue("ws");//$NON-NLS-1$
+ includedFeature.setWS(ws);
+
+ String arch = attributes.getValue("arch");//$NON-NLS-1$
+ includedFeature.setArch(arch);
+
+ // NL
+ String nl = attributes.getValue("nl"); //$NON-NLS-1$
+ includedFeature.setNL(nl);
+
+ objectStack.push(includedFeature);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
+ debug("End process Includes tag: id:" //$NON-NLS-1$
+ +id + " ver:" + ver); //$NON-NLS-1$
+ debug("name =" + name + " optional=" + optional + " search-location=" + locationName); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ debug("os=" + os + " ws=" + ws + " arch=" + arch); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+
+ /*
+ * process URL info with label attribute
+ */
+ private void processURLInfo(Attributes attributes) {
+ URLEntryModel inf = factory.createURLEntryModel();
+ String infoURL = attributes.getValue("url"); //$NON-NLS-1$
+ String label = attributes.getValue("label"); //$NON-NLS-1$
+ String type = attributes.getValue("type"); //$NON-NLS-1$
+ inf.setURLString(infoURL);
+ inf.setAnnotation(label);
+
+ if ("web".equalsIgnoreCase(type)) //$NON-NLS-1$
+ inf.setType(IURLEntry.WEB_SITE);
+ else
+ inf.setType(IURLEntry.UPDATE_SITE);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug("Processed URLInfo: url:" + infoURL + " label:" + label+" type:"+type);//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ objectStack.push(inf);
+ }
+
+ /*
+ * process import info
+ */
+ private void processImport(Attributes attributes) {
+ String pluginID = attributes.getValue("plugin"); //$NON-NLS-1$
+ String featureID = attributes.getValue("feature"); //$NON-NLS-1$
+ String idMatch = attributes.getValue("id-match"); //$NON-NLS-1$
+
+ if (!(pluginID == null ^ featureID == null)) {
+ internalError(Messages.DefaultFeatureParser_PluginAndFeatureId);
+ return;
+ }
+
+ // since 2.0.2 , manage feature and plugin import
+ String id = null;
+ if (pluginID == null) {
+ id = featureID;
+ } else {
+ id = pluginID;
+ }
+
+ if (id == null || id.trim().equals("")) //$NON-NLS-1$
+ internalError(NLS.bind(Messages.DefaultFeatureParser_MissingId, (new String[] { getState(currentState) })));
+ else {
+ String filter = attributes.getValue("filter");
+ String ver = attributes.getValue("version"); //$NON-NLS-1$
+ String match = attributes.getValue("match"); //$NON-NLS-1$
+ String patch = attributes.getValue("patch"); //$NON-NLS-1$
+
+ if (filter != null) {
+ //unsupported, ignore this element
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug(NLS.bind(UNSUPPORTED_FILTER_MSG, new String [] {IMPORT + ' ' + (pluginID != null ? PLUGIN : FEATURE), id, ver}));
+ ignoredElement = true;
+ return;
+ }
+ ImportModel imp = factory.createImportModel();
+
+ imp.setPatch(patch != null && patch.equalsIgnoreCase("true")); //$NON-NLS-1$
+
+ if (ver == null) {
+ if (imp.isPatch()) {
+ internalError(Messages.DefaultFeatureParser_MissingPatchVersion);
+ }
+ ver = "0.0.0"; //$NON-NLS-1$
+ match = "greaterOrEqual"; //$NON-NLS-1$
+ } else if (match == null) {
+ if (imp.isPatch())
+ match = "perfect"; //$NON-NLS-1$
+ else
+ match = "compatible"; //$NON-NLS-1$
+ }
+
+ imp.setIdentifier(id);
+ imp.setVersion(ver);
+ imp.setFeatureImport(featureID != null);
+ imp.setMatchingRuleName(match);
+ imp.setMatchingIdRuleName(idMatch);
+
+ if (imp.isPatch()) {
+ // patch reference must be perfect.
+ if (match != null && !match.equalsIgnoreCase("perfect")) { //$NON-NLS-1$
+ internalError(Messages.DefaultFeatureParser_wrongMatchForPatch);
+ }
+ if (imp.isFeatureImport() == false) {
+ imp.setPatch(false);
+ internalError(Messages.DefaultFeatureParser_patchWithPlugin);
+ }
+ }
+
+ // os arch ws
+ String os = attributes.getValue("os"); //$NON-NLS-1$
+ imp.setOS(os);
+
+ String ws = attributes.getValue("ws"); //$NON-NLS-1$
+ imp.setWS(ws);
+
+ String arch = attributes.getValue("arch"); //$NON-NLS-1$
+ imp.setOSArch(arch);
+
+ objectStack.push(imp);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
+ debug("Processed import: id:" + id + " ver:" + ver);//$NON-NLS-1$ //$NON-NLS-2$
+ debug("Processed import: match:" + match); //$NON-NLS-1$
+ }
+
+ }
+ }
+
+ /*
+ * process import info
+ */
+ private void processRequire(Attributes attributes) {
+ }
+
+ /*
+ * process plugin entry info
+ */
+ private void processPlugin(Attributes attributes) {
+ String id = attributes.getValue("id"); //$NON-NLS-1$
+ String ver = attributes.getValue("version"); //$NON-NLS-1$
+ if (id == null || id.trim().equals("") //$NON-NLS-1$
+ || ver == null || ver.trim().equals("")) { //$NON-NLS-1$
+ internalError(NLS.bind(Messages.DefaultFeatureParser_IdOrVersionInvalid, (new String[] { id, ver, getState(currentState)})));
+ } else {
+ String filter = attributes.getValue("filter");
+ if (filter != null) {
+ //unsupported, ignore this element
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ debug(NLS.bind(UNSUPPORTED_FILTER_MSG, new String [] {PLUGIN, id, ver}));
+ return;
+ }
+
+ PluginEntryModel pluginEntry = factory.createPluginEntryModel();
+ pluginEntry.setPluginIdentifier(id);
+ pluginEntry.setPluginVersion(ver);
+
+ String fragment = attributes.getValue("fragment"); //$NON-NLS-1$
+ pluginEntry.isFragment(fragment != null && fragment.trim().equalsIgnoreCase("true"));//$NON-NLS-1$
+
+ //setOS
+ String os = attributes.getValue("os"); //$NON-NLS-1$
+ pluginEntry.setOS(os);
+
+ //setWS
+ String ws = attributes.getValue("ws"); //$NON-NLS-1$
+ pluginEntry.setWS(ws);
+
+ //setNL
+ String nl = attributes.getValue("nl"); //$NON-NLS-1$
+ pluginEntry.setNL(nl);
+
+ // setArch
+ String arch = attributes.getValue("arch"); //$NON-NLS-1$
+ pluginEntry.setArch(arch);
+
+ // setUnpack
+ String unpack = attributes.getValue("unpack"); //$NON-NLS-1$
+ pluginEntry.setUnpack(!"false".equalsIgnoreCase(unpack)); //$NON-NLS-1$
+
+ // download size
+ long download_size = ContentEntryModel.UNKNOWN_SIZE;
+ String download = attributes.getValue("download-size"); //$NON-NLS-1$
+ if (download != null && !download.trim().equals("")) { //$NON-NLS-1$
+ try {
+ download_size = Long.valueOf(download).longValue();
+ } catch (NumberFormatException e) {
+ // use UNKNOWN_SIZE
+ }
+ }
+ pluginEntry.setDownloadSize(download_size);
+
+ // install size
+ long install_size = ContentEntryModel.UNKNOWN_SIZE;
+ String install = attributes.getValue("install-size"); //$NON-NLS-1$
+ if (install != null && !install.trim().equals("")) { //$NON-NLS-1$
+ try {
+ install_size = Long.valueOf(install).longValue();
+ } catch (NumberFormatException e) {
+ // use UNKNOWN_SIZE
+ }
+ }
+ pluginEntry.setInstallSize(install_size);
+
+ objectStack.push(pluginEntry);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
+ debug("Processed Plugin: id:" + id + " ver:" + ver + " fragment:" + fragment); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ debug("Processed Plugin: os:" + os + " ws:" + ws + " nl:" + nl); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ debug("Processed Plugin: download size:" //$NON-NLS-1$
+ +download_size + " install size:" //$NON-NLS-1$
+ +install_size);
+ }
+
+ }
+ }
+
+ /*
+ * process non-plug-in entry info
+ */
+ private void processData(Attributes attributes) {
+ String id = attributes.getValue("id"); //$NON-NLS-1$
+ if (id == null || id.trim().equals("")) { //$NON-NLS-1$
+ internalError(NLS.bind(Messages.DefaultFeatureParser_MissingId, (new String[] { getState(currentState) })));
+ } else {
+ NonPluginEntryModel dataEntry = factory.createNonPluginEntryModel();
+ dataEntry.setIdentifier(id);
+
+ //setOS
+ String os = attributes.getValue("os"); //$NON-NLS-1$
+ dataEntry.setOS(os);
+
+ //setWS
+ String ws = attributes.getValue("ws"); //$NON-NLS-1$
+ dataEntry.setWS(ws);
+
+ //setNL
+ String nl = attributes.getValue("nl"); //$NON-NLS-1$
+ dataEntry.setNL(nl);
+
+ // setArch
+ String arch = attributes.getValue("arch"); //$NON-NLS-1$
+ dataEntry.setArch(arch);
+
+ // download size
+ long download_size = ContentEntryModel.UNKNOWN_SIZE;
+ String download = attributes.getValue("download-size"); //$NON-NLS-1$
+ if (download != null && !download.trim().equals("")) { //$NON-NLS-1$
+ try {
+ download_size = Long.valueOf(download).longValue();
+ } catch (NumberFormatException e) {
+ // use UNKNOWN_SIZE
+ }
+ }
+ dataEntry.setDownloadSize(download_size);
+
+ // install size
+ long install_size = ContentEntryModel.UNKNOWN_SIZE;
+ String install = attributes.getValue("install-size"); //$NON-NLS-1$
+ if (install != null && !install.trim().equals("")) { //$NON-NLS-1$
+ try {
+ install_size = Long.valueOf(install).longValue();
+ } catch (NumberFormatException e) {
+ // use UNKNOWN_SIZE
+ }
+ }
+ dataEntry.setInstallSize(install_size);
+
+ objectStack.push(dataEntry);
+
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
+ debug("Processed Data: id:" + id); //$NON-NLS-1$
+ debug("Processed Data: download size:" //$NON-NLS-1$
+ +download_size + " install size:" //$NON-NLS-1$
+ +install_size);
+ }
+
+ }
+ }
+
+ private void debug(String s) {
+ UpdateCore.debug("InternalFeatureParser: " + s); //$NON-NLS-1$
+ }
+
+ private void logStatus(SAXParseException ex) {
+ String name = ex.getSystemId();
+ if (name == null)
+ name = ""; //$NON-NLS-1$
+ else
+ name = name.substring(1 + name.lastIndexOf("/")); //$NON-NLS-1$
+
+ String msg;
+ if (name.equals("")) { //$NON-NLS-1$
+ msg = NLS.bind(Messages.DefaultFeatureParser_ErrorParsing, (new String[] { ex.getMessage() }));
+ } else {
+ String[] values = new String[] { name, Integer.toString(ex.getLineNumber()), Integer.toString(ex.getColumnNumber()), ex.getMessage()};
+ msg = NLS.bind(Messages.DefaultFeatureParser_ErrorlineColumnMessage, values);
+ }
+ error(new Status(IStatus.ERROR, PLUGIN_ID, Platform.PARSE_PROBLEM, msg, ex));
+ }
+
+ /*
+ * Handles an error state specified by the status. The collection of all logged status
+ * objects can be accessed using <code>getStatus()</code>.
+ *
+ * @param error a status detailing the error condition
+ */
+ private void error(IStatus error) {
+
+ if (status == null) {
+ status = new MultiStatus(PLUGIN_ID, Platform.PARSE_PROBLEM, Messages.DefaultFeatureParser_ErrorParsingFeature, null);
+ }
+
+ status.add(error);
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING)
+ UpdateCore.log(error);
+ }
+
+ private void internalErrorUnknownTag(String msg) {
+ stateStack.push(new Integer(STATE_IGNORED_ELEMENT));
+ internalError(msg);
+ }
+
+ private void internalError(String message) {
+ if (location != null)
+ message += " " + NLS.bind(Messages.DefaultFeatureParser_location, (new String[] { location })); //$NON-NLS-1$
+ error(new Status(IStatus.ERROR, PLUGIN_ID, Platform.PARSE_PROBLEM, message, null));
+ }
+
+ /*
+ * return the state as String
+ */
+ private String getState(int state) {
+
+ switch (state) {
+ case STATE_IGNORED_ELEMENT :
+ return "Ignored"; //$NON-NLS-1$
+
+ case STATE_INITIAL :
+ return "Initial"; //$NON-NLS-1$
+
+ case STATE_FEATURE :
+ return "Feature"; //$NON-NLS-1$
+
+ case STATE_HANDLER :
+ return "Install Handler"; //$NON-NLS-1$
+
+ case STATE_DESCRIPTION :
+ return "description"; //$NON-NLS-1$
+
+ case STATE_INCLUDES :
+ return "includes"; //$NON-NLS-1$
+
+ case STATE_COPYRIGHT :
+ return "Copyright"; //$NON-NLS-1$
+
+ case STATE_LICENSE :
+ return "License"; //$NON-NLS-1$
+
+ case STATE_URL :
+ return "URL"; //$NON-NLS-1$
+
+ case STATE_UPDATE :
+ return "Update URL"; //$NON-NLS-1$
+
+ case STATE_DISCOVERY :
+ return "Discovery URL"; //$NON-NLS-1$
+
+ case STATE_REQUIRES :
+ return "Require"; //$NON-NLS-1$
+
+ case STATE_IMPORT :
+ return "Import"; //$NON-NLS-1$
+
+ case STATE_PLUGIN :
+ return "Plugin"; //$NON-NLS-1$
+
+ case STATE_DATA :
+ return "Data"; //$NON-NLS-1$
+
+ default :
+ return NLS.bind(Messages.DefaultFeatureParser_UnknownState, (new String[] { Integer.toString(state) }));
+ }
+
+ }
+
+ /**
+ * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
+ */
+ public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
+ super.ignorableWhitespace(arg0, arg1, arg2);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InternalSiteManager.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InternalSiteManager.java
new file mode 100644
index 0000000..f016501
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InternalSiteManager.java
@@ -0,0 +1,396 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.ILocalSite;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.ISiteFactory;
+import org.eclipse.update.core.ISiteFactoryExtension;
+import org.eclipse.update.core.JarContentReference;
+import org.eclipse.update.core.Site;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.core.model.InvalidSiteTypeException;
+import org.eclipse.update.internal.core.connection.ConnectionFactory;
+import org.eclipse.update.internal.core.connection.IResponse;
+import org.eclipse.update.internal.model.ITimestamp;
+
+/**
+ *
+ */
+public class InternalSiteManager {
+
+ public static ILocalSite localSite;
+
+ public static final String DEFAULT_SITE_TYPE = SiteURLContentProvider.SITE_TYPE;
+ private static final String DEFAULT_EXECUTABLE_SITE_TYPE = SiteFileContentProvider.SITE_TYPE;
+
+ private static Map estimates;
+
+ // cache found sites
+ private static Map sites = new HashMap();
+ // cache http updated url
+ private static Map httpSitesUpdatedUrls = new HashMap();
+ // cache timestamps
+ private static Map siteTimestamps = new HashMap();
+ public static boolean globalUseCache = true;
+
+ // true if an exception occured creating localSite
+ // so we cache it and don't attempt to create it again
+ private static CoreException exceptionOccured = null;
+
+ /*
+ * @see SiteManager#getLocalSite()
+ */
+ public static ILocalSite getLocalSite() throws CoreException {
+ return internalGetLocalSite();
+ }
+
+ /*
+ * Internal call if optimistic reconciliation needed
+ */
+ private static ILocalSite internalGetLocalSite() throws CoreException {
+
+ // if an exception occured while retrieving the Site
+ // rethrow it
+ if (exceptionOccured != null)
+ throw exceptionOccured;
+
+ if (localSite == null) {
+ try {
+ localSite = LocalSite.internalGetLocalSite();
+ } catch (CoreException e) {
+ exceptionOccured = e;
+ throw e;
+ }
+ }
+ return localSite;
+ }
+
+ private static boolean isValidCachedSite(URL siteURL) {
+ if (!sites.containsKey(siteURL.toExternalForm()))
+ return false;
+
+ Long timestamp = (Long)siteTimestamps.get(siteURL);
+ if (timestamp == null)
+ return false;
+ long localLastModified = timestamp.longValue();
+
+ return UpdateManagerUtils.isSameTimestamp(siteURL, localLastModified);
+ }
+
+ /*
+ * @see ILocalSite#getSite(URL)
+ */
+ public static ISite getSite(URL siteURL, boolean useCache, IProgressMonitor monitor) throws CoreException {
+ ISite site = null;
+ if (monitor==null) monitor = new NullProgressMonitor();
+
+ if (siteURL == null)
+ return null;
+
+ // use cache if set up globally (globalUseCache=true)
+ // and passed as parameter (useCache=true)
+ if (httpSitesUpdatedUrls.containsKey(siteURL.toExternalForm())) {
+ siteURL = (URL)httpSitesUpdatedUrls.get(siteURL.toExternalForm());
+ }
+ String siteURLString = siteURL.toExternalForm();
+ if ((useCache && globalUseCache) && isValidCachedSite(siteURL)) {
+ site = (ISite) sites.get(siteURLString);
+ UpdateCore.getPlugin().getUpdateSession().markVisited(site.getURL());
+ return site;
+ }
+
+ // try adding "eclipse" to the site url, in case this is an extension site
+ if ("file".equals(siteURL.getProtocol()) ) { //$NON-NLS-1$
+ File f = new File(siteURL.getFile());
+ if (f.isDirectory() && !"eclipse".equals(f.getName())) { //$NON-NLS-1$
+ f = new File(f, "eclipse"); //$NON-NLS-1$
+ try {
+ if ((useCache && globalUseCache) && isValidCachedSite(f.toURL())) {
+ site = (ISite) sites.get(f.toURL().toExternalForm());
+ return site;
+ }
+ } catch (MalformedURLException e) {
+ }
+ }
+ }
+
+ // consider file protocol also if the URL points to a directory
+ // and no site.xml exist
+ // if the user points to a file, consider DEFAULT_SITE_TYPE
+ // site.xml will have to specify the type
+ boolean fileProtocol = "file".equalsIgnoreCase(siteURL.getProtocol()); //$NON-NLS-1$
+ boolean directoryExists = false;
+ if (fileProtocol) {
+ File dir;
+ dir = new File(siteURL.getFile());
+ if (dir != null && dir.isDirectory()) {
+ if (!(new File(dir, Site.SITE_XML).exists()))
+ directoryExists = true;
+ }
+ }
+
+ //PERF: if file: <path>/ and directory exists then consider executable
+ monitor.beginTask(Messages.InternalSiteManager_ConnectingToSite, 8);
+ if (fileProtocol && directoryExists) {
+ site = attemptCreateSite(DEFAULT_EXECUTABLE_SITE_TYPE, siteURL, monitor);
+ monitor.worked(4); // only one attempt
+ } else {
+ try {
+ monitor.worked(3);
+ site = attemptCreateSite(DEFAULT_SITE_TYPE, siteURL, monitor);
+ monitor.worked(1);
+ } catch (CoreException preservedException) {
+ if (!monitor.isCanceled()) {
+ // attempt a retry is the protocol is file, with executbale type
+ if (!fileProtocol)
+ throw preservedException;
+
+ try {
+ site = attemptCreateSite(DEFAULT_EXECUTABLE_SITE_TYPE, siteURL, monitor);
+ } catch (CoreException retryException) {
+ IStatus firstStatus = preservedException.getStatus();
+ MultiStatus multi = new MultiStatus(firstStatus.getPlugin(), IStatus.OK, Messages.InternalSiteManager_FailedRetryAccessingSite, retryException);
+ multi.addAll(firstStatus);
+ throw preservedException;
+ }
+ }
+ }
+ }
+
+ if (site != null) {
+ sites.put(site.getURL().toExternalForm(), site);
+ UpdateCore.getPlugin().getUpdateSession().markVisited(site.getURL());
+ if (site instanceof ITimestamp) {
+ siteTimestamps.put(site.getURL(), new Long(((ITimestamp)site).getTimestamp().getTime()));
+ } else {
+ try {
+ IResponse response = ConnectionFactory.get(URLEncoder.encode(siteURL));
+ siteTimestamps.put(siteURL, new Long(response.getLastModified()));
+ } catch (MalformedURLException e) {
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ //flush the JarFile we may hold on to
+ // we keep the temp not to create them again
+ JarContentReference.shutdown(); // make sure we are not leaving jars open for this site
+
+ //flush mapping of downloaded JAR files
+ // FIXME : provide better cache flushing after 2.1
+ // FIXED: everything downloaded is cached and timestamped.
+ // Timestamps are compared to lastModifed on the server
+ // and we download only when there is a differenc
+ // Utilities.flushLocalFile();
+
+ return site;
+ }
+
+ /*
+ * Attempt to create a site
+ * if the site guessed is not the type found,
+ * attempt to create a type with the type found in the site.xml
+ */
+ private static ISite attemptCreateSite(String guessedTypeSite, URL siteURL, IProgressMonitor monitor) throws CoreException {
+ if (monitor == null) monitor = new NullProgressMonitor();
+ ISite site = null;
+
+ try {
+ monitor.worked(1);
+ site = createSite(guessedTypeSite, siteURL, monitor);
+ monitor.worked(1); // if no error, occurs the retry branch doesn't need to be executed
+ } catch (InvalidSiteTypeException e) {
+ if (monitor.isCanceled()) return null;
+
+ // the type in the site.xml is not the one expected
+ // attempt to use this type instead
+ //DEBUG:
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_TYPE) {
+ UpdateCore.debug("The Site :" + siteURL.toExternalForm() + " is a different type than the guessed type based on the protocol. new Type:" + e.getNewType()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ try {
+ if (e.getNewType() == null)
+ throw e;
+ site = createSite(e.getNewType(), siteURL, monitor);
+ } catch (InvalidSiteTypeException e1) {
+ throw Utilities.newCoreException(NLS.bind(Messages.InternalSiteManager_UnableToCreateSiteWithType, (new String[] { e.getNewType(), siteURL.toExternalForm() })), e1);
+ }
+ }
+
+ return site;
+ }
+
+ /*
+ * create an instance of a class that implements ISite
+ *
+ * the URL can be of the following form
+ * 1 protocol://...../
+ * 2 protocol://.....
+ * 3 protocol://..../site.xml
+ * 4 protocol://...#...
+ *
+ * 1 If the file of the file of teh url ends with '/', attempt to open the stream.
+ * if it fails, add site.xml and attempt to open the stream
+ *
+ * 2 attempt to open the stream
+ * fail
+ * add '/site.xml' and attempt to open the stream
+ * sucess
+ * attempt to parse, if it fails, add '/site.xml' and attempt to open the stream
+ *
+ * 3 open the stream
+ *
+ * 4 open the stream
+ */
+ private static ISite createSite(String siteType, URL url, IProgressMonitor monitor) throws CoreException, InvalidSiteTypeException {
+
+ if (monitor == null) monitor = new NullProgressMonitor();
+ //ISite site = null;
+ ISiteFactory factory = SiteTypeFactory.getInstance().getFactory(siteType);
+ URL fixedUrl;
+
+ // see if we need to (and can) fix url by adding site.xml to it
+ try {
+ if ( (url.getRef() != null) || (url.getFile().endsWith(Site.SITE_XML) || (url.getProtocol().equalsIgnoreCase("file")))) { //$NON-NLS-1$
+ fixedUrl = url;
+ } else if (url.getFile().endsWith("/")) { //$NON-NLS-1$
+ fixedUrl = new URL(url, Site.SITE_XML);
+ } else {
+ fixedUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile() + "/" + Site.SITE_XML); //$NON-NLS-1$
+ }
+ } catch (MalformedURLException mue) {
+ fixedUrl = url;
+ }
+
+ try {
+ try {
+ monitor.worked(1);
+ return createSite( factory, fixedUrl, url, monitor);
+ } catch (CoreException ce) {
+ if (monitor.isCanceled())
+ return null;
+
+ if (!fixedUrl.equals(url)) {
+ // try with original url
+ return createSite( factory, url, url, monitor);
+ } else if (url.getProtocol().equalsIgnoreCase("file") && ! url.getFile().endsWith(Site.SITE_XML)){ //$NON-NLS-1$
+ try {
+ if (url.getFile().endsWith("/")) { //$NON-NLS-1$
+ return createSite(factory, new URL(url,
+ Site.SITE_XML), url, monitor);
+ } else {
+ return createSite(factory, new URL(url
+ .getProtocol(), url.getHost(), url
+ .getPort(), url.getFile()
+ + "/" + Site.SITE_XML), url, monitor); //$NON-NLS-1$
+ }
+ } catch (MalformedURLException mue) {
+ throw ce;
+ }
+ } else {
+ throw ce;
+ }
+ }
+ } catch(CoreException ce) {
+ throw Utilities.newCoreException(NLS.bind(Messages.InternalSiteManager_UnableToAccessURL, (new String[] { url.toExternalForm() })), ce);
+ }
+ }
+
+ private static ISite createSite(ISiteFactory factory, URL url, URL originalUrl, IProgressMonitor monitor) throws CoreException, InvalidSiteTypeException {
+
+ ISite site;
+
+ site = createSite(factory, url, monitor);
+ httpSitesUpdatedUrls.put(originalUrl.toExternalForm(), url);
+
+ return site;
+ }
+
+ private static ISite createSite(ISiteFactory factory, URL url, IProgressMonitor monitor) throws CoreException, InvalidSiteTypeException {
+ if (factory instanceof ISiteFactoryExtension)
+ return ((ISiteFactoryExtension)factory).createSite(url, monitor);
+ else
+ return factory.createSite(url);
+ }
+
+ /*
+ * Creates a new site on the file system
+ * This is the only Site we can create.
+ *
+ * @param siteLocation
+ * @throws CoreException
+ */
+ public static ISite createSite(File siteLocation) throws CoreException {
+ ISite site = null;
+ if (siteLocation != null) {
+ try {
+ URL siteURL = siteLocation.toURL();
+ site = getSite(siteURL, false, null);
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.InternalSiteManager_UnableToCreateURL, (new String[] { siteLocation.getAbsolutePath() })), e);
+ }
+ }
+ return site;
+ }
+
+
+ /**
+ * Method downloaded.
+ * @param downloadSize size downloaded in bytes
+ * @param time time in seconds
+ * @param url
+ */
+ public static void downloaded(long downloadSize, long time, URL url) {
+ if (downloadSize <= 0 || time < 0)
+ return;
+ String host = url.getHost();
+ long sizeByTime = (time == 0) ? 0 : downloadSize / time;
+ Long value = new Long(sizeByTime);
+ if (estimates == null) {
+ estimates = new HashMap();
+ } else {
+ Long previous = (Long) estimates.get(host);
+ if (previous != null) {
+ value = new Long((previous.longValue() + sizeByTime) / 2);
+ }
+ }
+ estimates.put(host, value);
+ }
+ /**
+ * Method getEstimatedTransferRate rate bytes/seconds.
+ * @param host
+ * @return long
+ */
+ public static long getEstimatedTransferRate(String host) {
+ if (estimates == null)
+ return 0;
+ Long value = (Long) estimates.get(host);
+ if (value == null)
+ return 0;
+ return value.longValue();
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/JarDeltaInstallHandler.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/JarDeltaInstallHandler.java
new file mode 100644
index 0000000..d1a7e34
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/JarDeltaInstallHandler.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.update.core.IFeatureContentConsumer;
+import org.eclipse.update.core.IPluginEntry;
+import org.eclipse.update.core.PluginEntry;
+import org.eclipse.update.core.Site;
+
+public class JarDeltaInstallHandler extends DeltaInstallHandler {
+
+
+ protected void overlayPlugin(
+ IPluginEntry oldPlugin,
+ IPluginEntry newPlugin,
+ IFeatureContentConsumer consumer)
+ throws CoreException, IOException {
+
+ if(newPlugin instanceof PluginEntry && ((PluginEntry)newPlugin).isUnpack()){
+ // partial plug-ins (in patches) must always be unpacked
+ super.overlayPlugin(oldPlugin, newPlugin, consumer);
+ }
+
+ URL oldURI = null;
+ try {
+ oldURI = new URL(consumer.getFeature().getSite().getURL().getPath() +
+ Site.DEFAULT_PLUGIN_PATH +
+ oldPlugin.getVersionedIdentifier().toString());
+ } catch (MalformedURLException e) {
+ throw new IOException(e.getMessage());
+ }
+ File oldJarFile = new File(oldURI.toExternalForm());
+ JarFile oldJar = new JarFile(oldJarFile);
+
+ URL newURI = null;
+ try {
+ newURI = new URL(consumer.getFeature().getSite().getURL().getPath() +
+ Site.DEFAULT_PLUGIN_PATH +
+ newPlugin.getVersionedIdentifier().toString());
+ } catch (MalformedURLException e) {
+ throw new IOException(e.getMessage());
+ }
+ File newJarFile = new File(newURI.toExternalForm());
+ JarFile newJar = new JarFile(newJarFile);
+
+ String tempFileName = oldURI + "-" + (new Date()).getTime(); //$NON-NLS-1$
+ File tempFile = new File(tempFileName);
+ FileOutputStream fos = new FileOutputStream(tempFile);
+ JarOutputStream jos = new JarOutputStream( fos);
+
+ addToJar(jos, newJar);
+ addToJar(jos, oldJar);
+
+ jos.closeEntry();
+ jos.finish();
+ fos.close();
+ newJar.close();
+ oldJar.close();
+
+ newJarFile = new File(newURI.toExternalForm());
+ newJarFile.delete();
+
+ newJarFile.createNewFile();
+
+ copyFile(tempFile, newJarFile);
+ }
+
+ public static void copyFile(File src, File dst) throws IOException {
+ InputStream in=null;
+ OutputStream out=null;
+ try {
+ in = new BufferedInputStream(new FileInputStream(src));
+ out = new BufferedOutputStream(new FileOutputStream(dst));
+ byte[] buffer = new byte[4096];
+ int len;
+ while ((len=in.read(buffer)) != -1) {
+ out.write(buffer, 0, len);
+ }
+ } finally {
+ if (in != null)
+ try {
+ in.close();
+ } catch (IOException e) {
+ }
+ if (out != null)
+ try {
+ out.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ public static void addToJar(JarOutputStream jos, JarFile jf) throws IOException {
+ Enumeration e = jf.entries();
+
+ while(e.hasMoreElements()) {
+
+ ZipEntry je = (ZipEntry)e.nextElement();
+ InputStream io = jf.getInputStream(je);
+
+ byte b[] = new byte[4096];
+ int read = 0;
+ try {
+ jos.putNextEntry(je);
+ while( ( read = io.read(b, 0, 4096)) != -1) {
+ jos.write(b, 0, read);
+ }
+ } catch (ZipException ze) {
+ //ze.printStackTrace();
+ throw ze;
+ }
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/LiteFeature.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/LiteFeature.java
new file mode 100644
index 0000000..25ac09f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/LiteFeature.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * 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.update.internal.core;
+
+import org.eclipse.update.core.Feature;
+
+public class LiteFeature extends Feature {
+
+ private boolean fullFeature = true;
+
+ public boolean isFullFeature() {
+ return fullFeature;
+ }
+
+ public void setFullFeature(boolean fullFeature) {
+ this.fullFeature = fullFeature;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/LiteFeatureFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/LiteFeatureFactory.java
new file mode 100644
index 0000000..0f0a9ee
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/LiteFeatureFactory.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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.update.internal.core;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.update.core.BaseFeatureFactory;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.model.FeatureModel;
+
+public class LiteFeatureFactory extends BaseFeatureFactory {
+
+ public LiteFeatureFactory() {
+ super();
+ }
+
+ public IFeature createFeature(URL url, ISite site, IProgressMonitor monitor)
+ throws CoreException {
+
+ return null;
+ }
+
+ public FeatureModel createFeatureModel() {
+ return new LiteFeature();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/LocalSite.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/LocalSite.java
new file mode 100644
index 0000000..c41697d
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/LocalSite.java
@@ -0,0 +1,374 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.core;
+
+import org.eclipse.core.runtime.ListenerList;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Date;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.IActivity;
+import org.eclipse.update.configuration.IInstallConfiguration;
+import org.eclipse.update.configuration.ILocalSite;
+import org.eclipse.update.configuration.ILocalSiteChangedListener;
+import org.eclipse.update.configuration.IProblemHandler;
+import org.eclipse.update.configurator.ConfiguratorUtils;
+import org.eclipse.update.configurator.IPlatformConfiguration;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.internal.model.InstallConfigurationModel;
+import org.eclipse.update.internal.model.SiteLocalModel;
+import org.eclipse.update.internal.model.SiteLocalParser;
+
+/**
+ * This class manages the configurations.
+ */
+
+public class LocalSite extends SiteLocalModel implements ILocalSite{
+
+ private ListenerList listeners = new ListenerList(ListenerList.IDENTITY);
+ private SiteStatusAnalyzer siteStatusAnalyzer;
+ private boolean isTransient = false;
+
+ /*
+ * Have new features been found during reconciliation
+ */
+ public static boolean newFeaturesFound = false;
+
+ /*
+ * initialize the configurations from the persistent model.
+ * Set the reconciliation as non optimistic
+ */
+ public static ILocalSite getLocalSite() throws CoreException {
+ return internalGetLocalSite();
+ }
+
+ /*
+ *Internal call is reconciliation needs to be optimistic
+ */
+ public static ILocalSite internalGetLocalSite() throws CoreException {
+
+ LocalSite localSite = new LocalSite();
+
+ // obtain platform configuration
+ IPlatformConfiguration currentPlatformConfiguration = ConfiguratorUtils.getCurrentPlatformConfiguration();
+ localSite.isTransient(currentPlatformConfiguration.isTransient());
+
+ try {
+ URL configXML = currentPlatformConfiguration.getConfigurationLocation();
+ localSite.setLocationURLString(configXML.toExternalForm());
+ localSite.resolve(configXML, null);
+
+ // Attempt to read previous state
+ parseLocalSiteFile(currentPlatformConfiguration, localSite);
+
+ } catch (MalformedURLException exception) {
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteLocal_UnableToCreateURLFor, (new String[] { localSite.getLocationURLString() + " & " + CONFIG_FILE })), exception); //$NON-NLS-1$
+ }
+
+ return localSite;
+ }
+
+ /**
+ * Create the localSite object
+ */
+ private static boolean parseLocalSiteFile(IPlatformConfiguration platformConfig, LocalSite localSite ) throws CoreException, MalformedURLException {
+
+ //attempt to parse the LocalSite.xml
+// URL resolvedURL = URLEncoder.encode(configXML);
+ try {
+// InputStream in = UpdateCore.getPlugin().get(resolvedURL).getInputStream();
+ new SiteLocalParser(platformConfig, localSite);
+ return true;
+ } catch (Exception exception) {
+ return false;
+ }
+ }
+
+ /**
+ *
+ */
+ protected LocalSite() {
+ }
+
+ /**
+ * adds a new configuration to the LocalSite
+ * the newly added configuration is teh current one
+ */
+ public void addConfiguration(IInstallConfiguration config) {
+ if (config != null) {
+ addConfigurationModel((InstallConfigurationModel) config);
+
+ trimHistoryToCapacity();
+
+ // set configuration as current
+ if (getCurrentConfigurationModel() != null)
+ getCurrentConfigurationModel().setCurrent(false);
+ if (config instanceof InstallConfiguration)
+ ((InstallConfiguration) config).setCurrent(true);
+
+ setCurrentConfigurationModel((InstallConfigurationModel) config);
+ ((InstallConfigurationModel) config).markReadOnly();
+
+ // notify listeners
+ Object[] siteLocalListeners = listeners.getListeners();
+ for (int i = 0; i < siteLocalListeners.length; i++) {
+ ((ILocalSiteChangedListener) siteLocalListeners[i]).currentInstallConfigurationChanged(config);
+ }
+ }
+
+ }
+
+ /*
+ *
+ */
+ private void trimHistoryToCapacity() {
+ // check if we have to remove a configuration
+ // the first added is #0
+ while (getConfigurationHistory().length > getMaximumHistoryCount() &&
+ getConfigurationHistory().length > 1) {
+ // do not remove the first element in history, this is the original config
+ InstallConfigurationModel removedConfig = getConfigurationHistoryModel()[1];
+ if (removeConfigurationModel(removedConfig)) {
+
+ // DEBUG:
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION) {
+ UpdateCore.debug("Removed configuration :" + removedConfig.getLabel()); //$NON-NLS-1$
+ }
+
+ // notify listeners
+ Object[] siteLocalListeners = listeners.getListeners();
+ for (int i = 0; i < siteLocalListeners.length; i++) {
+ ((ILocalSiteChangedListener) siteLocalListeners[i]).installConfigurationRemoved((IInstallConfiguration) removedConfig);
+ }
+
+ //remove files
+ URL url = removedConfig.getURL();
+ UpdateManagerUtils.removeFromFileSystem(new File(url.getFile()));
+ }
+ }
+ }
+ /*
+ * @see ILocalSite#addLocalSiteChangedListener(ILocalSiteChangedListener)
+ */
+ public void addLocalSiteChangedListener(ILocalSiteChangedListener listener) {
+ listeners.add(listener);
+ }
+
+ /*
+ * @see ILocalSite#removeLocalSiteChangedListener(ILocalSiteChangedListener)
+ */
+ public void removeLocalSiteChangedListener(ILocalSiteChangedListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Saves the site into the config file.
+ * @return true if changes restart is needed
+ */
+ public boolean save() throws CoreException {
+
+ // Save the current configuration as
+ // the other are already saved
+ // and set runtim info for next startup
+ return ((InstallConfiguration) getCurrentConfiguration()).save();
+ }
+
+// /**
+// * Method createNewInstallConfiguration.
+// * @return IInstallConfiguration
+// */
+// private IInstallConfiguration createNewInstallConfiguration() throws CoreException {
+// InstallConfiguration newInstallConfig = createConfigurationSite(null);
+// newInstallConfig.setTimeline(newInstallConfig.getCreationDate().getTime());
+// return newInstallConfig;
+// }
+
+
+ /**
+ * @since 2.0
+ * @deprecated This method should not be used. The current install configuration is to be used.
+ */
+ public IInstallConfiguration cloneCurrentConfiguration() throws CoreException {
+ try {
+ return new InstallConfiguration(getCurrentConfiguration());
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(Messages.SiteLocal_cloneConfig, e);
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void revertTo(IInstallConfiguration configuration, IProgressMonitor monitor, IProblemHandler handler) throws CoreException {
+
+ // create the activity
+ //Start UOW ?
+ ConfigurationActivity activity = new ConfigurationActivity(IActivity.ACTION_REVERT);
+ activity.setLabel(configuration.getLabel());
+ activity.setDate(new Date());
+ IInstallConfiguration newConfiguration = null;
+
+ try {
+ // create a configuration
+ newConfiguration = cloneCurrentConfiguration();
+ newConfiguration.setLabel(configuration.getLabel());
+
+ // add to the stack which will set up as current
+ addConfiguration(newConfiguration);
+
+ // process delta
+ // the Configured featuresConfigured are the same as the old configuration
+ // the unconfigured featuresConfigured are the rest...
+ ((InstallConfiguration) newConfiguration).revertTo(configuration, monitor, handler);
+
+ // everything done ok
+ activity.setStatus(IActivity.STATUS_OK);
+ } catch (CoreException e) {
+ // error
+ activity.setStatus(IActivity.STATUS_NOK);
+ throw e;
+ } catch (InterruptedException e) {
+ //user decided not to revert, do nothing
+ // because we didn't add the configuration to the history
+ } finally {
+ if (newConfiguration != null)
+ ((InstallConfiguration) newConfiguration).addActivity(activity);
+ }
+
+ }
+
+ /**
+ * @since 2.0
+ * @deprecated
+ */
+ public IInstallConfiguration addToPreservedConfigurations(IInstallConfiguration configuration) throws CoreException {
+ return null;
+ }
+
+ /*
+ * @see ILocalSite#getPreservedConfigurationFor(IInstallConfiguration)
+ */
+ public IInstallConfiguration findPreservedConfigurationFor(IInstallConfiguration configuration) {
+
+ // based on time stamp for now
+ InstallConfigurationModel preservedConfig = null;
+ if (configuration != null) {
+ InstallConfigurationModel[] preservedConfigurations = getPreservedConfigurationsModel();
+ if (preservedConfigurations != null) {
+ for (int indexPreserved = 0; indexPreserved < preservedConfigurations.length; indexPreserved++) {
+ if (configuration.getCreationDate().equals(preservedConfigurations[indexPreserved].getCreationDate())) {
+ preservedConfig = preservedConfigurations[indexPreserved];
+ break;
+ }
+ }
+ }
+ }
+
+ return (IInstallConfiguration) preservedConfig;
+ }
+
+ /*
+ * @see ILocalSite#getCurrentConfiguration()
+ * LocalSiteModel#getCurrentConfigurationModel() may return null if
+ * we just parsed LocalSite.xml
+ */
+ public IInstallConfiguration getCurrentConfiguration() {
+ if (getCurrentConfigurationModel() == null) {
+ int index = 0;
+ if ((index = getConfigurationHistoryModel().length) == 0) {
+ return null;
+ } else {
+ InstallConfigurationModel config = getConfigurationHistoryModel()[index - 1];
+ config.setCurrent(true);
+ setCurrentConfigurationModel(config);
+ }
+ }
+ return (IInstallConfiguration) getCurrentConfigurationModel();
+ }
+
+ /*
+ * @see ILocalSite#getPreservedConfigurations()
+ */
+ public IInstallConfiguration[] getPreservedConfigurations() {
+ if (getPreservedConfigurationsModel().length == 0)
+ return new IInstallConfiguration[0];
+ return (IInstallConfiguration[]) getPreservedConfigurationsModel();
+ }
+
+ /*
+ * @see ILocalSite#removeFromPreservedConfigurations(IInstallConfiguration)
+ */
+ public void removeFromPreservedConfigurations(IInstallConfiguration configuration) {
+ if (removePreservedConfigurationModel((InstallConfigurationModel) configuration))
+ ((InstallConfiguration) configuration).remove();
+ }
+
+ /*
+ * @see ILocalSite#getConfigurationHistory()
+ */
+ public IInstallConfiguration[] getConfigurationHistory() {
+ if (getConfigurationHistoryModel().length == 0)
+ return new IInstallConfiguration[0];
+ return (IInstallConfiguration[]) getConfigurationHistoryModel();
+ }
+
+
+ /**
+ * Gets the isTransient.
+ * @return Returns a boolean
+ */
+ public boolean isTransient() {
+ return isTransient;
+ }
+
+ /**
+ * Sets the isTransient.
+ * @param isTransient The isTransient to set
+ */
+ private void isTransient(boolean isTransient) {
+ this.isTransient = isTransient;
+ }
+
+ /*
+ *
+ */
+ private SiteStatusAnalyzer getSiteStatusAnalyzer() {
+ if (siteStatusAnalyzer == null)
+ siteStatusAnalyzer = new SiteStatusAnalyzer(this);
+ return siteStatusAnalyzer;
+ }
+
+ /*
+ * check if the Plugins of the feature are on the plugin path
+ * If all the plugins are on the plugin path, and the version match and there is no other version -> HAPPY
+ * If all the plugins are on the plugin path, and the version match and there is other version -> AMBIGUOUS
+ * If some of the plugins are on the plugin path, but not all -> UNHAPPY
+ * Check on all ConfiguredSites
+ */
+ public IStatus getFeatureStatus(IFeature feature) throws CoreException {
+ return getSiteStatusAnalyzer().getFeatureStatus(feature);
+ }
+ /**
+ * @see org.eclipse.update.internal.model.SiteLocalModel#setMaximumHistoryCount(int)
+ */
+ public void setMaximumHistoryCount(int history) {
+ super.setMaximumHistoryCount(history);
+ trimHistoryToCapacity();
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/LockManager.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/LockManager.java
new file mode 100644
index 0000000..f1abe5d
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/LockManager.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.update.internal.core;
+
+import java.util.Hashtable;
+
+/**
+ * @author aniefer
+ *
+ */
+public class LockManager {
+ // lock
+ private final static Object lock = new Object();
+
+ // hashtable of locks
+ private static Hashtable locks = new Hashtable();
+
+ public static Object getLock(String key) {
+ synchronized (lock) {
+ if (locks.get(key) == null)
+ locks.put(key, key);
+ return locks.get(key);
+ }
+ }
+
+ public static void returnLock(String key) {
+ synchronized (lock) {
+ locks.remove(key);
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/Messages.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/Messages.java
new file mode 100644
index 0000000..bee325b
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/Messages.java
@@ -0,0 +1,289 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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.update.internal.core;
+
+import org.eclipse.osgi.util.NLS;
+
+public final class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.update.internal.core.messages";//$NON-NLS-1$
+
+ private Messages() {
+ // Do not instantiate
+ }
+
+ public static String BaseSiteFactory_CannotRetriveParentDirectory;
+ public static String ContentReference_UnableToCreateInputStream;
+ public static String ContentReference_UnableToReturnReferenceAsFile;
+ public static String ContentReference_UnableToReturnReferenceAsURL;
+ public static String ContentReference_HttpNok;
+ public static String ContentReference_FileDoesNotExist;
+ public static String Feature_SiteAlreadySet;
+ public static String Feature_TaskInstallFeatureFiles;
+ public static String Feature_TaskInstallPluginFiles;
+ public static String Feature_NoContentProvider;
+ public static String Feature_NoFeatureContentConsumer;
+ public static String Feature_NoURL;
+ public static String Feature_FeatureVersionToString;
+ public static String Feature_InstallationCancelled;
+ public static String Feature_UnableToInitializeFeatureReference;
+ public static String FeatureContentProvider_Downloading;
+ public static String FeatureContentProvider_UnableToRetrieve;
+ public static String FeatureContentProvider_UnableToCreate;
+ public static String FeatureContentProvider_ExceptionDownloading;
+ public static String InstallHandler_unableToCreateHandler;
+ public static String InstallHandler_notFound;
+ public static String InstallHandler_invalidHandler;
+ public static String InstallHandler_callException;
+ public static String InstallHandler_error;
+ public static String InstallMonitor_DownloadSize;
+ public static String InstallMonitor_DownloadSizeLong;
+ public static String ProductProvider;
+ public static String JarContentReference_Unpacking;
+ public static String Site_CannotFindCategory;
+ public static String Site_NoCategories;
+ public static String Site_NoContentProvider;
+ public static String VersionedIdentifier_IdOrVersionNull;
+ public static String SiteFile_CannotRemovePlugin;
+ public static String SiteFile_CannotRemoveFeature;
+ public static String SiteFile_UnableToCreateURL;
+ public static String SiteFile_Removing;
+ public static String SiteFileFactory_UnableToCreateURL;
+ public static String SiteFileFactory_UnableToAccessSite;
+ public static String SiteFileFactory_DirectoryDoesNotExist;
+ public static String DefaultFeatureParser_location;
+ public static String DefaultFeatureParser_NoFeatureTag;
+ public static String DefaultFeatureParser_WrongParsingStack;
+ public static String DefaultFeatureParser_UnknownElement;
+ public static String DefaultFeatureParser_TooManyURLtag;
+ public static String DefaultFeatureParser_UnknownStartState;
+ public static String DefaultFeatureParser_IdOrVersionInvalid;
+ public static String DefaultFeatureParser_MissingId;
+ public static String DefaultFeatureParser_ParsingStackBackToInitialState;
+ public static String DefaultFeatureParser_ElementAlreadySet;
+ public static String DefaultFeatureParser_StateIncludeWrongElement;
+ public static String DefaultFeatureParser_RequireStateWithoutImportElement;
+ public static String DefaultFeatureParser_MissingPatchVersion;
+ public static String DefaultFeatureParser_wrongMatchForPatch;
+ public static String DefaultFeatureParser_patchWithPlugin;
+ public static String DefaultFeatureParser_MultiplePatchImports;
+ public static String DefaultFeatureParser_UnknownEndState;
+ public static String DefaultFeatureParser_ErrorParsing;
+ public static String DefaultFeatureParser_ErrorlineColumnMessage;
+ public static String DefaultFeatureParser_ErrorParsingFeature;
+ public static String DefaultFeatureParser_UnknownState;
+ public static String DefaultFeatureParser_NoLicenseText;
+ public static String DefaultFeatureParser_PluginAndFeatureId;
+ public static String SiteContentProvider_ErrorCreatingURLForArchiveID;
+ public static String DefaultSiteParser_NoSiteTag;
+ public static String DefaultSiteParser_WrongParsingStack;
+ public static String DefaultSiteParser_UnknownElement;
+ public static String DefaultSiteParser_UnknownStartState;
+ public static String DefaultSiteParser_Missing;
+ public static String DefaultSiteParser_ParsingStackBackToInitialState;
+ public static String DefaultSiteParser_ElementAlreadySet;
+ public static String DefaultSiteParser_UnknownEndState;
+ public static String DefaultSiteParser_ErrorParsing;
+ public static String DefaultSiteParser_ErrorlineColumnMessage;
+ public static String DefaultSiteParser_ErrorParsingSite;
+ public static String DefaultSiteParser_UnknownState;
+ public static String DefaultSiteParser_InvalidXMLStream;
+ public static String ModelObject_ModelReadOnly;
+ public static String SiteModelObject_ErrorParsingSiteStream;
+ public static String SiteModelObject_ErrorAccessingSiteStream;
+ public static String InstallConfiguration_ErrorDuringFileAccess;
+ public static String InstallConfigurationParser_FeatureReferenceNoURL;
+ public static String FeatureExecutableContentProvider_FileDoesNotExist;
+ public static String FeatureExecutableContentProvider_InvalidDirectory;
+ public static String FeatureExecutableContentProvider_UnableToCreateURLFor;
+ public static String FeatureExecutableContentProvider_UnableToRetrieveNonPluginEntry;
+ public static String FeatureExecutableContentProvider_UnableToRetrieveFeatureEntry;
+ public static String FeatureExecutableContentProvider_UnableToRetrievePluginEntry;
+ public static String ConfiguredSite_NonInstallableSite;
+ public static String ConfiguredSite_NullFeatureToInstall;
+ public static String ConfiguredSite_NonUninstallableSite;
+ public static String ConfiguredSite_NoSite;
+ public static String ConfiguredSite_CannotFindFeatureToUnconfigure;
+ public static String ConfiguredSite_CannotFindFeatureToConfigure;
+ public static String ConfiguredSite_CannotFindPluginEntry;
+ public static String ConfiguredSite_MissingPluginsBrokenFeature;
+ public static String ConfiguredSite_UnableToRemoveConfiguredFeature;
+ public static String ConfiguredSite_UnableToFindFeature;
+ public static String ConfiguredSite_SiteURLNull;
+ public static String ConfiguredSite_NonLocalSite;
+ public static String ConfiguredSite_NotSameProductId;
+ public static String ConfiguredSite_ContainedInAnotherSite;
+ public static String ConfiguredSite_ReadOnlySite;
+ public static String ConfiguredSite_UnableResolveURL;
+ public static String ConfiguredSite_UnableToAccessSite;
+ public static String FeatureFactory_CreatingError;
+ public static String FeatureModelFactory_ErrorAccesingFeatureStream;
+ public static String FeatureExecutableFactory_NullURL;
+ public static String FeatureExecutableFactory_CannotCreateURL;
+ public static String FeaturePackagedContentProvider_NoManifestFile;
+ public static String FeaturePackagedContentProvider_InvalidDirectory;
+ public static String FeaturePackagedContentProvider_ErrorRetrieving;
+ public static String FeatureReference_UnableToResolveURL;
+ public static String FeatureTypeFactory_UnableToFindFeatureFactory;
+ public static String InstallConfiguration_UnableToCreateURL;
+ public static String InstallConfiguration_UnableToCast;
+ public static String InstallConfiguration_UnableToSavePlatformConfiguration;
+ public static String InstallConfiguration_AlreadyNativelyLinked;
+ public static String InstallConfiguration_AlreadyProductSite;
+ public static String InstallConfiguration_unableToFindSite;
+ public static String InternalSiteManager_UnableToCreateSiteWithType;
+ public static String InternalSiteManager_UnableToAccessURL;
+ public static String InternalSiteManager_UnableToCreateURL;
+ public static String InternalSiteManager_FailedRetryAccessingSite;
+ public static String InternalSiteManager_ConnectingToSite;
+ public static String GlobalConsumer_ErrorCreatingFile;
+ public static String SiteFileContentConsumer_UnableToCreateURL;
+ public static String SiteFileContentConsumer_UnableToCreateURLForFile;
+ public static String SiteFileContentConsumer_unableToDelete;
+ public static String ContentConsumer_UnableToRename;
+ public static String SiteFileFactory_UnableToObtainParentDirectory;
+ public static String SiteFileFactory_FileDoesNotExist;
+ public static String SiteFileFactory_UnableToCreateURLForFile;
+ public static String SiteFileFactory_ErrorParsingFile;
+ public static String SiteFileFactory_ErrorAccessing;
+ public static String SiteTypeFactory_UnableToFindSiteFactory;
+ public static String UpdateManagerUtils_UnableToRemoveFile;
+ public static String UpdateManagerUtils_FileAlreadyExists;
+ public static String SiteLocal_UnableToCreateURLFor;
+ public static String SiteLocal_UnableToDetermineFeatureStatusSiteNull;
+ public static String SiteLocal_TwoVersionSamePlugin1;
+ public static String SiteLocal_TwoVersionSamePlugin2;
+ public static String SiteLocal_FeatureUnHappy;
+ public static String SiteLocal_FeatureHappy;
+ public static String SiteLocal_FeatureAmbiguous;
+ public static String SiteLocal_NestedFeatureUnHappy;
+ public static String SiteLocal_NestedFeatureUnavailable;
+ public static String SiteLocal_NoPluginVersion;
+ public static String SiteLocal_UnableToDetermineFeatureStatusConfiguredSiteNull;
+ public static String SiteLocal_FeatureDisable;
+ public static String SiteLocal_FeatureStatusUnknown;
+ public static String SiteLocal_NestedFeatureDisable;
+ public static String SiteURLFactory_UnableToCreateURL;
+ public static String SiteURLFactory_UnableToAccessSiteStream;
+ public static String JarVerifier_Verify;
+ public static String JarVerifier_UnableToFindEncryption;
+ public static String JarVerifier_UnableToLoadCertificate;
+ public static String JarVerifier_UnableToFindProviderForKeystore;
+ public static String JarVerifier_KeyStoreNotLoaded;
+ public static String JarVerifier_UnableToAccessJar;
+ public static String JarVerifier_InvalidFile;
+ public static String JarVerifier_InvalidJar;
+ public static String JarVerificationResult_ValidBetween;
+ public static String JarVerificationResult_ExpiredCertificate;
+ public static String JarVerificationResult_CertificateNotYetValid;
+ public static String JarVerificationResult_CertificateValid;
+ public static String JarVerificationService_UnsucessfulVerification;
+ public static String JarVerificationService_CancelInstall;
+ public static String UpdateManagerUtils_UnableToLog;
+ public static String ConnectionThreadManager_tooManyConnections;
+ public static String ConnectionThreadManager_unresponsiveURL;
+ public static String IncludedFeatureReference_featureUninstalled;
+ public static String ActivityConstraints_warning;
+ public static String ActivityConstraints_rootMessage;
+ public static String ActivityConstraints_rootMessageInitial;
+ public static String ActivityConstraints_beforeMessage;
+ public static String ActivityConstraints_afterMessage;
+ public static String ActivityConstraints_platform;
+ public static String ActivityConstraints_primary;
+ public static String ActivityConstaints_prereq_plugin;
+ public static String ActivityConstaints_prereq_feature;
+ public static String ActivityConstraints_prereq;
+ public static String ActivityConstraints_prereqPerfect;
+ public static String ActivityConstraints_prereqEquivalent;
+ public static String ActivityConstraints_prereqCompatible;
+ public static String ActivityConstraints_prereqGreaterOrEqual;
+ public static String ActivityConstraints_os;
+ public static String ActivityConstraints_ws;
+ public static String ActivityConstraints_arch;
+ public static String ActivityConstraints_cycle;
+ public static String ActivityConstraints_childMessage;
+ public static String ActivityConstraints_optionalChild;
+ public static String ActivityConstraints_exclusive;
+ public static String ActivityConstraints_noLicense;
+ public static String ActivityConstraints_readOnly;
+ public static String ActivityConstraints_platformModified;
+ public static String DuplicateConflictsDialog_conflict;
+ public static String OperationsManager_error_old;
+ public static String OperationsManager_installing;
+ public static String OperationsManager_error_uninstall;
+ public static String Search_networkProblems;
+ public static String InstallConfiguration_location_exists;
+ public static String InstallLogParser_errors;
+ public static String SiteLocal_cloneConfig;
+ public static String UpdateManagerUtils_inputStreamEnded;
+ public static String UpdateSearchRequest_loadingPolicy;
+ public static String UpdateManagerUtils_copy;
+ public static String UpdatePolicy_parsePolicy;
+ public static String UpdatePolicy_policyExpected;
+ public static String UpdateSearchRequest_searching;
+ public static String UpdateSearchRequest_contacting;
+ public static String UpdateSearchRequest_checking;
+ public static String UpdatePolicy_invalidURL;
+ public static String UpdatePolicy_nameNoNull;
+ public static String UpdatePolicy_UpdatePolicy;
+ public static String SiteFile_featureNotRemoved;
+ public static String SiteFile_pluginNotRemoved;
+ public static String ErrorRecoveryLog_noFiletoRemove;
+ public static String UpdatesSearchCategory_errorSearchingForUpdates;
+ public static String UninstallCommand_featureNotInstalledByUM;
+ public static String Standalone_siteConfigured;
+ public static String Standalone_noSite;
+ public static String Standalone_noSite3;
+ public static String Standalone_noConfiguredSite;
+ public static String Standalone_installing;
+ public static String Standalone_notFoundOrNewer;
+ public static String Standalone_duplicate;
+ public static String Standalone_installed;
+ public static String Standalone_cannotInstall;
+ public static String Standalone_noFeatures1;
+ public static String Standalone_noFeatures2;
+ public static String Standalone_noFeatures3;
+ public static String Standalone_noFeatures4;
+ public static String Standalone_noConfigSiteForFeature;
+ public static String Standalone_invalidCmd;
+ public static String Standalone_connection;
+ public static String Standalone_searching;
+ public static String Standalone_cmdFailed;
+ public static String Standalone_cmdFailedNoLog;
+ public static String Standalone_cmdCompleteWithErrors;
+ public static String Standalone_cmdOK;
+ public static String Standalone_updating;
+ public static String Standalone_noUpdate;
+ public static String Standalone_updated;
+
+ public static String SiteFilePluginContentConsumer_unableToDelete;
+ public static String SiteFilePackedPluginContentConsumer_unableToDelete;
+
+ public static String HttpResponse_rangeExpected;
+ public static String HttpResponse_wrongRange;
+ public static String DefaultSiteParser_mirrors;
+ public static String FeatureExecutableContentProvider_UnableToRetriveArchiveContentRef;
+
+ public static String JarProcessor_unpackNotFound;
+ public static String JarProcessor_noPackUnpack;
+ public static String JarProcessor_packNotFound;
+
+ public static String SiteOptimizer_inputNotSpecified;
+ public static String SiteOptimizer_inputFileNotFound;
+ public static String SiteCategory_other_label;
+ public static String SiteCategory_other_description;
+
+ static {
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ public static String InstallCommand_site;
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/NonPluginEntryContentConsumer.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/NonPluginEntryContentConsumer.java
new file mode 100644
index 0000000..e040188
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/NonPluginEntryContentConsumer.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+
+/**
+ * ContentConsumer for a non plugin entry of a feature
+ */
+
+public class NonPluginEntryContentConsumer extends ContentConsumer {
+
+ private boolean closed = false;
+
+ private IContentConsumer contentConsumer;
+
+ /*
+ * Constructor
+ */
+ public NonPluginEntryContentConsumer(IContentConsumer contentConsumer){
+ this.contentConsumer = contentConsumer;
+ }
+
+ /*
+ * @see ContentConsumer#store(ContentReference, IProgressMonitor)
+ */
+ public void store(ContentReference contentReference, IProgressMonitor monitor) throws CoreException {
+ if (!closed){
+ contentConsumer.store( contentReference,monitor);
+ } else {
+ UpdateCore.warn("Attempt to store in a closed NonPluginEntryContentConsumer",new Exception()); //$NON-NLS-1$
+ }
+ }
+
+ /*
+ * @see ContentConsumer#close()
+ */
+ public void close() throws CoreException {
+ if (!closed){
+ closed = true;
+ contentConsumer.close();
+ } else {
+ UpdateCore.warn("Attempt to close a closed NonPluginEntryContentConsumer",new Exception()); //$NON-NLS-1$
+ }
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/NullContentReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/NullContentReference.java
new file mode 100644
index 0000000..963fa1d
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/NullContentReference.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * 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.update.internal.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.eclipse.update.core.ContentReference;
+
+/**
+ * NullContentReference implements a general access wrapper
+ * to feature and site content -- but, for which, there is no
+ * content actually found. This way, it can "keep" the ID that was
+ * requested, and still hold a place in lists and arrays, without a
+ * change to other program logic. It does, how ever require the internal
+ * algorithms to be more careful about assumptions made ... for example,
+ * just because asFile is null, it does not follow that asURL will not be null.
+ * <p>
+ * This class may not be instantiated or subclassed by clients.
+ * </p>
+ * @see org.eclipse.update.core.ContentReference
+ * @see org.eclipse.update.core.JarContentReference
+ * @see org.eclipse.update.core.JarEntryContentReference
+ */
+public class NullContentReference extends ContentReference {
+
+
+ /**
+ * Contructor for the "missing jar" case.
+ *
+ * @param id
+ */
+ public NullContentReference(String id) {
+ super(id, (File) null);
+ }
+ /**
+ * A factory method to create a content reference of
+ * the same type.
+ *
+ * @param id "symbolic" path identifier
+ */
+ public ContentReference createContentReference(String id, File file) {
+ return new NullContentReference(id);
+ }
+
+ /**
+ * Overrides super class implementation to avoid throwing a FileNotFound exception.
+ *
+ * @return null
+ */
+ public InputStream getInputStream() throws IOException {
+ return null;
+ }
+ /**
+ * Overrides super class implementation to avoid throwing a FileNotFound exception.
+ *
+ * @return null
+ */
+ public File asFile() throws IOException {
+ return null;
+ }
+
+ /**
+ * Overrides super class implementation to avoid throwing URL exceptions.
+ *
+ * @return null
+ */
+ public URL asURL() throws IOException {
+ return null;
+ }
+
+ /**
+ * Return string representation of this reference.
+ *
+ * @return string representation
+ */
+ public String toString() {
+ return "Missing archive file: " + '(' + getIdentifier() + ')'; //$NON-NLS-1$
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/PatchedFeature.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/PatchedFeature.java
new file mode 100644
index 0000000..bc9dae9
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/PatchedFeature.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+/**
+ * Feature and corresponding patch features
+ */
+public class PatchedFeature {
+ private IFeatureReference feature;
+ private Collection patches = new HashSet();
+ /**
+ *
+ */
+ public PatchedFeature(IFeatureReference feature) {
+ super();
+ this.feature = feature;
+ }
+ public void addPatch(IFeatureReference patch) {
+ patches.add(patch);
+ }
+ /**
+ * @return Returns the feature.
+ */
+ public IFeatureReference getFeature() {
+ return feature;
+ }
+ /**
+ * @return Returns the patches.
+ */
+ public IFeatureReference[] getPatches() {
+ return (IFeatureReference[]) patches.toArray(new IFeatureReference[patches.size()]);
+ }
+ /**
+ * @return Returns the feature and the patches.
+ */
+ public IFeatureReference[] getFeatureAndPatches() {
+ IFeatureReference[] features = new IFeatureReference[patches.size() + 1];
+ features[0] = feature;
+ System.arraycopy(getPatches(), 0, features, 1, patches.size());
+ return features;
+ }
+ /**
+ * Obtains all plugins from the feature and its patches. Each plugin will
+ * have unique ID.
+ * If there are multiple version of plugin with same ID among the feature
+ * and its patches, highest version plugins are chosen.
+ *
+ * @return FeaturePlugin[]
+ */
+ public FeaturePlugin[] getPlugins() {
+ // Use a map of PatchedPluigns by plugin ID
+ // to collect one version of each plugin
+ Map plugins = new HashMap();
+ IFeatureReference[] featureRefs = getFeatureAndPatches();
+ // for each (feature or any patch)
+ for (int i = 0; i < featureRefs.length; i++) {
+ try {
+ IFeature feature = featureRefs[i].getFeature(null);
+ if (feature == null) {
+ UpdateCore.warn("Null Feature", new Exception()); //$NON-NLS-1$
+ continue;
+ }
+ // get plugin entries
+ IPluginEntry[] entries = feature.getPluginEntries();
+ for (int entr = 0; entr < entries.length; entr++) {
+ String pluginId = entries[entr].getVersionedIdentifier().getIdentifier();
+ PluginVersionIdentifier pluginVersion = entries[entr].getVersionedIdentifier().getVersion();
+ // check if map contains >= version of same plugin
+ FeaturePlugin existingPlugin = (FeaturePlugin) plugins.get(pluginId);
+ if (existingPlugin != null && existingPlugin.getEntry().getVersionedIdentifier().getVersion().isGreaterOrEqualTo(pluginVersion)) {
+ // same or newer plugin already collected
+ continue;
+ } else {
+ plugins.put(pluginId, new FeaturePlugin(entries[entr], feature));
+ }
+ }
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ }
+ }
+ return (FeaturePlugin[]) plugins.values().toArray(new FeaturePlugin[plugins.size()]);
+ }
+ public String toString() {
+ StringBuffer str = new StringBuffer(feature.toString());
+ IFeatureReference[] patches = getFeatureAndPatches();
+ for (int i = 0; i < patches.length; i++) {
+ str.append(" +patch=" + patches[i].toString() + " "); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return str.toString();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/PluginEntryContentConsumer.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/PluginEntryContentConsumer.java
new file mode 100644
index 0000000..a549ee5
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/PluginEntryContentConsumer.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+
+/**
+ * ContentConsumer for a plugin entry of a feature
+ */
+
+public class PluginEntryContentConsumer extends ContentConsumer {
+
+ private boolean closed = false;
+
+ private IContentConsumer contentConsumer;
+
+ /*
+ * Constructor
+ */
+ public PluginEntryContentConsumer(IContentConsumer contentConsumer){
+ this.contentConsumer = contentConsumer;
+ }
+
+ /*
+ * @see ContentConsumer#store(ContentReference, IProgressMonitor)
+ */
+ public void store(ContentReference contentReference, IProgressMonitor monitor) throws CoreException {
+ if (!closed){
+ contentConsumer.store(contentReference,monitor);
+ } else {
+ UpdateCore.warn("Attempt to store in a closed PluginEntryContentConsumer",new Exception()); //$NON-NLS-1$
+ }
+ }
+
+ /*
+ * @see ContentConsumer#close()
+ */
+ public void close() throws CoreException {
+ if (!closed){
+ closed = true;
+ contentConsumer.close();
+ } else {
+ UpdateCore.warn("Attempt to close a closed PluginEntryContentConsumer",new Exception()); //$NON-NLS-1$
+ }
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ProductProvider.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ProductProvider.java
new file mode 100644
index 0000000..da84d80
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ProductProvider.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * 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.update.internal.core;
+
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configurator.*;
+import org.eclipse.update.internal.configurator.FeatureEntry;
+
+/**
+ * Maps primary features to IProduct
+ */
+public class ProductProvider implements IProductProvider {
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IProductProvider#getProducts()
+ */
+ public IProduct[] getProducts() {
+ IPlatformConfiguration configuration = ConfiguratorUtils.getCurrentPlatformConfiguration();
+ if (configuration == null)
+ return new IProduct[0];
+ IPlatformConfiguration.IFeatureEntry[] features = configuration.getConfiguredFeatureEntries();
+ ArrayList primaryFeatures = new ArrayList();
+ for (int i = 0; i < features.length; i++)
+ if (features[i].canBePrimary() && (features[i] instanceof FeatureEntry))
+ primaryFeatures.add(new FeatureEntryWrapper((FeatureEntry) features[i]));
+ // TODO handle unmanaged plugins later
+ return (IProduct[]) primaryFeatures.toArray(new IProduct[primaryFeatures.size()]);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IProductProvider#getName()
+ */
+ public String getName() {
+ return Messages.ProductProvider;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteContentConsumer.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteContentConsumer.java
new file mode 100644
index 0000000..3c121cd
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteContentConsumer.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+
+
+import org.eclipse.update.core.*;
+
+/**
+ * A default implementation for IFeatureContentConsumer
+ * </p>
+ * @since 2.0
+ */
+
+public abstract class SiteContentConsumer implements ISiteContentConsumer {
+
+ private ISite site;
+
+ /*
+ * @see ISiteContentConsumer#setSite(ISite)
+ */
+ /**
+ * Sets the site.
+ * @param site The site to set
+ */
+ public void setSite(ISite site) {
+ this.site = site;
+ }
+
+ /**
+ * Gets the site.
+ * @return Returns a ISite
+ */
+ public ISite getSite() {
+ return site;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFile.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFile.java
new file mode 100644
index 0000000..29c6f31
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFile.java
@@ -0,0 +1,424 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.core;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.ContentReference;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IFeatureContentConsumer;
+import org.eclipse.update.core.IFeatureFactory;
+import org.eclipse.update.core.IFeatureReference;
+import org.eclipse.update.core.IInstallHandler;
+import org.eclipse.update.core.INonPluginEntry;
+import org.eclipse.update.core.IPluginEntry;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.ISiteFeatureReference;
+import org.eclipse.update.core.IVerificationListener;
+import org.eclipse.update.core.IVerifier;
+import org.eclipse.update.core.InstallMonitor;
+import org.eclipse.update.core.Site;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.core.model.ContentEntryModel;
+import org.eclipse.update.core.model.FeatureModel;
+import org.eclipse.update.core.model.FeatureReferenceModel;
+import org.eclipse.update.core.model.InstallAbortedException;
+import org.eclipse.update.internal.operations.UpdateUtils;
+
+
+/**
+ * Site on the File System
+ */
+public class SiteFile extends Site {
+
+ /**
+ * plugin entries
+ */
+ private List pluginEntries = new ArrayList(0);
+
+ /**
+ *
+ */
+ public ISiteContentConsumer createSiteContentConsumer(IFeature targetFeature) throws CoreException {
+ SiteFileContentConsumer consumer = new SiteFileContentConsumer(targetFeature);
+ consumer.setSite(this);
+ return consumer;
+ }
+
+ /**
+ */
+ public String getDefaultPackagedFeatureType() {
+ return DEFAULT_INSTALLED_FEATURE_TYPE;
+ }
+
+ /*
+ * @see ISite#install(IFeature, IVerifier, IProgressMonitor)
+ */
+ public IFeatureReference install(IFeature sourceFeature, IVerificationListener verificationListener, IProgressMonitor progress) throws CoreException {
+ return install(sourceFeature,null,verificationListener,progress);
+ }
+
+ /*
+ * @see ISite#install(IFeature, IVerifier, IProgressMonitor)
+ */
+ public IFeatureReference install(IFeature sourceFeature, IFeatureReference[] optionalfeatures, IVerificationListener verificationListener, IProgressMonitor progress) throws CoreException {
+
+ if (sourceFeature == null)
+ return null;
+
+ // make sure we have an InstallMonitor
+ InstallMonitor monitor;
+ if (progress == null)
+ monitor = null;
+ else if (progress instanceof InstallMonitor)
+ monitor = (InstallMonitor) progress;
+ else
+ monitor = new InstallMonitor(progress);
+
+ // create new executable feature and install source content into it
+ IFeature localFeature = createExecutableFeature(sourceFeature);
+
+ IFeatureReference localFeatureReference = null;
+ localFeatureReference = sourceFeature.install(localFeature, optionalfeatures, verificationListener, monitor);
+
+ return localFeatureReference;
+ }
+
+ /*
+ * @see ISite#install(IFeature,IFeatureContentConsumer, IVerifier,IVerificationLIstener, IProgressMonitor)
+ */
+ public IFeatureReference install(IFeature sourceFeature, IFeatureReference[] optionalfeatures, IFeatureContentConsumer parentContentConsumer, IVerifier parentVerifier, IVerificationListener verificationListener, IProgressMonitor progress)
+ throws InstallAbortedException, CoreException {
+
+ if (sourceFeature == null)
+ return null;
+
+ // make sure we have an InstallMonitor
+ InstallMonitor monitor;
+ if (progress == null)
+ monitor = null;
+ else if (progress instanceof InstallMonitor)
+ monitor = (InstallMonitor) progress;
+ else
+ monitor = new InstallMonitor(progress);
+
+ // create new executable feature and install source content into it
+ IFeature localFeature = createExecutableFeature(sourceFeature);
+ parentContentConsumer.addChild(localFeature);
+
+ // set the verifier
+ IVerifier vr = sourceFeature.getFeatureContentProvider().getVerifier();
+ if (vr != null)
+ vr.setParent(parentVerifier);
+
+ IFeatureReference localFeatureReference = null;
+ localFeatureReference = sourceFeature.install(localFeature, optionalfeatures, verificationListener, monitor);
+
+ return localFeatureReference;
+ }
+
+ /*
+ * @see ISite#remove(IFeature, IProgressMonitor)
+ */
+ public void remove(IFeature feature, IProgressMonitor progress) throws CoreException {
+
+ if (feature == null) {
+ UpdateCore.warn("Feature to remove is null"); //$NON-NLS-1$
+ return;
+ }
+
+ ErrorRecoveryLog recoveryLog = ErrorRecoveryLog.getLog();
+
+ // make sure we have an InstallMonitor
+ InstallMonitor monitor;
+ if (progress == null)
+ monitor = null;
+ else if (progress instanceof InstallMonitor)
+ monitor = (InstallMonitor) progress;
+ else
+ monitor = new InstallMonitor(progress);
+
+ // Setup optional install handler
+ InstallHandlerProxy handler = new InstallHandlerProxy(IInstallHandler.HANDLER_ACTION_UNINSTALL, feature, feature.getInstallHandlerEntry(), monitor);
+ boolean success = false;
+ Throwable originalException = null;
+
+ try {
+
+ // start log
+ recoveryLog.open(ErrorRecoveryLog.START_REMOVE_LOG);
+
+ // log files have been downloaded
+ recoveryLog.append(ErrorRecoveryLog.END_ABOUT_REMOVE);
+
+ handler.uninstallInitiated();
+
+ // remove the feature and the plugins if they are not used and not activated
+ // get the plugins from the feature
+ IPluginEntry[] pluginsToRemove = getPluginEntriesOnlyReferencedBy(feature);
+
+ if (monitor != null) {
+ monitor.beginTask(Messages.SiteFile_Removing + feature.getLabel(), pluginsToRemove.length + 1);
+ }
+
+ // remove feature reference from the site
+ ISiteFeatureReference[] featureReferences = getFeatureReferences();
+ if (featureReferences != null) {
+ for (int indexRef = 0; indexRef < featureReferences.length; indexRef++) {
+ IFeatureReference element = featureReferences[indexRef];
+ if (element.getVersionedIdentifier().equals(feature.getVersionedIdentifier())) {
+ removeFeatureReferenceModel((FeatureReferenceModel) element);
+ break;
+ }
+ }
+ }
+
+ if (InstallRegistry.getInstance().get("feature_"+feature.getVersionedIdentifier()) == null) { //$NON-NLS-1$
+ UpdateCore.log(NLS.bind(Messages.SiteFile_featureNotRemoved, (new String[] { feature.getVersionedIdentifier().toString() })), null);
+ } else {
+ // remove the feature content
+ ContentReference[] references = feature.getFeatureContentProvider().getFeatureEntryArchiveReferences(monitor);
+ for (int i = 0; i < references.length; i++) {
+ try {
+ UpdateManagerUtils.removeFromFileSystem(references[i].asFile());
+ if (monitor != null)
+ monitor.worked(1);
+ } catch (IOException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteFile_CannotRemoveFeature, (new String[] { feature.getVersionedIdentifier().getIdentifier(), getURL().toExternalForm() })), e);
+ }
+ }
+ InstallRegistry.unregisterFeature(feature);
+ }
+
+ //finds the contentReferences for an IPluginEntry
+ // and remove it
+ for (int i = 0; i < pluginsToRemove.length; i++) {
+ remove(feature, pluginsToRemove[i], monitor);
+ }
+
+ // remove any children feature
+ IFeatureReference[] childrenRef = feature.getIncludedFeatureReferences();
+ for (int i = 0; i < childrenRef.length; i++) {
+ IFeature childFeature = null;
+ try {
+ childFeature = childrenRef[i].getFeature(null);
+ } catch (CoreException e) {
+ UpdateCore.warn("Unable to retrieve feature to remove for:" + childrenRef[i]); //$NON-NLS-1$
+ }
+ // do not remove nested feature if configured (i.e. used by another configured feature)
+ if (childFeature != null && !getCurrentConfiguredSite().isConfigured(childFeature))
+ remove(childrenRef[i].getFeature(null), monitor);
+ }
+
+ // remove the feature from the site cache
+ removeFeatureFromCache(feature.getURL());
+
+ handler.completeUninstall();
+
+ success = true;
+ } catch (Throwable t) {
+ originalException = t;
+ } finally {
+ Throwable newException = null;
+ try {
+ if (success) {
+ // close the log
+ recoveryLog.close(ErrorRecoveryLog.END_REMOVE_LOG);
+ recoveryLog.delete();
+ } else {
+ recoveryLog.close(ErrorRecoveryLog.END_REMOVE_LOG);
+ }
+ handler.uninstallCompleted(success);
+ } catch (Throwable t) {
+ newException = t;
+ }
+ if (originalException != null) // original exception wins
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallHandler_error, (new String[] { feature.getLabel() })), originalException);
+ if (newException != null)
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallHandler_error, (new String[] { feature.getLabel() })), newException);
+ }
+ }
+
+ /**
+ * returns the download size
+ * of the feature to be installed on the site.
+ * If the site is <code>null</code> returns the maximum size
+ *
+ * If one plug-in entry has an unknown size.
+ * then the download size is unknown.
+ *
+ */
+ public long getDownloadSizeFor(IFeature feature) {
+ long result = 0;
+ //[132029]
+ //IPluginEntry[] entriesToInstall = feature.getPluginEntries();
+ //IPluginEntry[] siteEntries = this.getPluginEntries();
+ //entriesToInstall = UpdateManagerUtils.diff(entriesToInstall, siteEntries);
+ //[18355]
+ //INonPluginEntry[] nonPluginEntriesToInstall = feature.getNonPluginEntries();
+
+ try {
+ //[132029]
+ //result = feature.getFeatureContentProvider().getDownloadSizeFor(entriesToInstall, nonPluginEntriesToInstall);
+ IFeatureReference[] children = feature.getIncludedFeatureReferences();
+ IFeature currentFeature = null;
+ for (int i = 0; i < children.length; i++) {
+ currentFeature = UpdateUtils.getIncludedFeature(feature, children[i]);
+ if (currentFeature != null) {
+ result += getDownloadSizeFor(currentFeature);
+ if(result == ContentEntryModel.UNKNOWN_SIZE)
+ return result;
+ }
+ }
+
+ IPluginEntry[] entriesToInstall = feature.getPluginEntries();
+ IPluginEntry[] siteEntries = this.getPluginEntries();
+ entriesToInstall = UpdateManagerUtils.diff(entriesToInstall, siteEntries);
+ //[18355]
+ INonPluginEntry[] nonPluginEntriesToInstall = feature.getNonPluginEntries();
+
+ result += feature.getFeatureContentProvider().getDownloadSizeFor(entriesToInstall, nonPluginEntriesToInstall);
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ result = ContentEntryModel.UNKNOWN_SIZE;
+ }
+ return result;
+ }
+
+ /**
+ * returns the download size
+ * of the feature to be installed on the site.
+ * If the site is <code>null</code> returns the maximum size
+ *
+ * If one plug-in entry has an unknown size.
+ * then the download size is unknown.
+ *
+ * @see ISite#getDownloadSizeFor(IFeature)
+ *
+ */
+ public long getInstallSizeFor(IFeature feature) {
+ long result = 0;
+
+ try {
+ List pluginsToInstall = new ArrayList();
+
+ // get all the plugins [17304]
+ pluginsToInstall.addAll(Arrays.asList(feature.getPluginEntries()));
+ IFeatureReference[] children = feature.getIncludedFeatureReferences();
+ IFeature currentFeature = null;
+ for (int i = 0; i < children.length; i++) {
+ currentFeature = UpdateUtils.getIncludedFeature(feature, children[i]);
+ if (currentFeature != null) {
+ //[132029]
+ //pluginsToInstall.addAll(Arrays.asList(currentFeature.getPluginEntries()));
+ result += getInstallSizeFor(currentFeature);
+ if (result == ContentEntryModel.UNKNOWN_SIZE)
+ return result;
+ }
+ }
+
+ IPluginEntry[] entriesToInstall = new IPluginEntry[0];
+ if (pluginsToInstall.size() > 0) {
+ entriesToInstall = new IPluginEntry[pluginsToInstall.size()];
+ pluginsToInstall.toArray(entriesToInstall);
+ }
+
+ IPluginEntry[] siteEntries = this.getPluginEntries();
+ entriesToInstall = UpdateManagerUtils.diff(entriesToInstall, siteEntries);
+
+ //[18355]
+ INonPluginEntry[] nonPluginEntriesToInstall = feature.getNonPluginEntries();
+
+ //[132029]
+ //result = feature.getFeatureContentProvider().getInstallSizeFor(entriesToInstall, nonPluginEntriesToInstall);
+ result += feature.getFeatureContentProvider().getInstallSizeFor(entriesToInstall, nonPluginEntriesToInstall);
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ result = ContentEntryModel.UNKNOWN_SIZE;
+ }
+
+ return result;
+ }
+
+ /**
+ * Adds a plugin entry
+ * Either from parsing the file system or
+ * installing a feature
+ *
+ * We cannot figure out the list of plugins by reading the Site.xml as
+ * the archives tag are optionals
+ */
+ public void addPluginEntry(IPluginEntry pluginEntry) {
+ pluginEntries.add(pluginEntry);
+ }
+
+ public IPluginEntry[] getPluginEntries() {
+ IPluginEntry[] result = new IPluginEntry[0];
+ if (!(pluginEntries == null || pluginEntries.isEmpty())) {
+ result = new IPluginEntry[pluginEntries.size()];
+ pluginEntries.toArray(result);
+ }
+ return result;
+ }
+
+
+ public int getPluginEntryCount() {
+ return getPluginEntries().length;
+ }
+
+ /**
+ *
+ */
+ private IFeature createExecutableFeature(IFeature sourceFeature) throws CoreException {
+ IFeature result = null;
+ IFeatureFactory factory = FeatureTypeFactory.getInstance().getFactory(DEFAULT_INSTALLED_FEATURE_TYPE);
+ result = factory.createFeature(/*URL*/null, this, null);
+
+ // at least set the version identifier to be the same
+ ((FeatureModel) result).setFeatureIdentifier(sourceFeature.getVersionedIdentifier().getIdentifier());
+ ((FeatureModel) result).setFeatureVersion(sourceFeature.getVersionedIdentifier().getVersion().toString());
+ return result;
+ }
+
+ /**
+ *
+ */
+ private void remove(IFeature feature, IPluginEntry pluginEntry, InstallMonitor monitor) throws CoreException {
+
+ if (pluginEntry == null)
+ return;
+
+ if (InstallRegistry.getInstance().get("plugin_"+pluginEntry.getVersionedIdentifier()) == null) { //$NON-NLS-1$
+ UpdateCore.log(NLS.bind(Messages.SiteFile_pluginNotRemoved, (new String[] { pluginEntry.getVersionedIdentifier().toString() })), null);
+ return;
+ }
+
+ ContentReference[] references = feature.getFeatureContentProvider().getPluginEntryArchiveReferences(pluginEntry, monitor);
+ for (int i = 0; i < references.length; i++) {
+ try {
+ UpdateManagerUtils.removeFromFileSystem(references[i].asFile());
+ if (monitor != null)
+ monitor.worked(1);
+ } catch (IOException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteFile_CannotRemovePlugin, (new String[] { pluginEntry.getVersionedIdentifier().toString(), getURL().toExternalForm() })), e);
+ }
+ }
+ pluginEntries.remove(pluginEntry);
+ InstallRegistry.unregisterPlugin(pluginEntry);
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFileContentConsumer.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFileContentConsumer.java
new file mode 100644
index 0000000..d1e4139
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFileContentConsumer.java
@@ -0,0 +1,313 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.core;
+
+import org.eclipse.update.core.FeatureContentProvider;
+
+import java.io.*;
+import java.net.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+import org.eclipse.update.core.model.*;
+
+/**
+ * ContentConsummer for a SiteFile
+ */
+public class SiteFileContentConsumer extends SiteContentConsumer {
+
+ private IFeature feature;
+ private boolean closed = false;
+
+ // recovery
+ private String oldPath;
+ private String newPath;
+
+ // for abort
+ private List /* of SiteFilePluginContentConsumer */
+ contentConsumers;
+ private List /*of path as String */
+ installedFiles;
+
+ // PERF: new instance variable
+ private SiteFileFactory archiveFactory = new SiteFileFactory();
+
+ /*
+ * Constructor
+ */
+ public SiteFileContentConsumer(IFeature feature) {
+ this.feature = feature;
+ installedFiles = new ArrayList();
+ }
+
+ /*
+ * Returns the path in which the Feature will be installed
+ */
+ private String getFeaturePath() throws CoreException {
+ String featurePath = null;
+ try {
+ VersionedIdentifier featureIdentifier = feature.getVersionedIdentifier();
+ String path = Site.DEFAULT_INSTALLED_FEATURE_PATH + featureIdentifier.toString() + File.separator;
+ URL newURL = new URL(getSite().getURL(), path);
+ featurePath = newURL.getFile();
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(Messages.SiteFileContentConsumer_UnableToCreateURL + e.getMessage(), e);
+ }
+ return featurePath;
+ }
+
+ /*
+ * @see ISiteContentConsumer#open(INonPluginEntry)
+ */
+ public IContentConsumer open(INonPluginEntry nonPluginEntry) throws CoreException {
+ return new SiteFileNonPluginContentConsumer(getFeaturePath());
+ }
+
+ /*
+ * @see ISiteContentConsumer#open(IPluginEntry)
+ */
+ public IContentConsumer open(IPluginEntry pluginEntry) throws CoreException {
+ ContentConsumer cons;
+ if(pluginEntry instanceof PluginEntryModel && !((PluginEntryModel)pluginEntry).isUnpack()){
+ // plugin can run from a jar
+ cons = new SiteFilePackedPluginContentConsumer(pluginEntry, getSite());
+ } else{
+ // plugin must be unpacked
+ cons = new SiteFilePluginContentConsumer(pluginEntry, getSite());
+ }
+ addContentConsumers(cons);
+ return cons;
+ }
+
+ /*
+ * @see ISiteContentConsumer#store(ContentReference, IProgressMonitor)
+ */
+ public void store(ContentReference contentReference, IProgressMonitor monitor) throws CoreException {
+
+ if (closed) {
+ UpdateCore.warn("Attempt to store in a closed SiteFileContentConsumer", new Exception()); //$NON-NLS-1$
+ return;
+ }
+
+ InputStream inStream = null;
+ String featurePath = getFeaturePath();
+ String contentKey = contentReference.getIdentifier();
+ featurePath += contentKey;
+
+ // error recovery
+ if (featurePath.endsWith("\\"+Feature.FEATURE_XML) || featurePath.endsWith("/"+Feature.FEATURE_XML)) { //$NON-NLS-1$ //$NON-NLS-2$
+ oldPath = featurePath.replace(File.separatorChar, '/');
+ File localFile = new File(oldPath);
+ if (localFile.exists()) {
+ throw Utilities.newCoreException(NLS.bind(Messages.UpdateManagerUtils_FileAlreadyExists, (new Object[] { localFile })), null);
+ }
+ featurePath = ErrorRecoveryLog.getLocalRandomIdentifier(featurePath);
+ newPath = featurePath;
+ ErrorRecoveryLog.getLog().appendPath(ErrorRecoveryLog.FEATURE_ENTRY, featurePath);
+ }
+
+ try {
+ inStream = contentReference.getInputStream();
+ UpdateManagerUtils.copyToLocal(inStream, featurePath, null);
+ UpdateManagerUtils.checkPermissions(contentReference, featurePath); // 20305
+ installedFiles.add(featurePath);
+ } catch (IOException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.GlobalConsumer_ErrorCreatingFile, (new String[] { featurePath })), e);
+ } finally {
+ if (inStream != null) {
+ try {
+ // close stream
+ inStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ }
+
+ /*
+ * @see ISiteContentConsumer#close()
+ */
+ public IFeatureReference close() throws CoreException {
+
+ if (closed)
+ UpdateCore.warn("Attempt to close a closed SiteFileContentConsumer", new Exception()); //$NON-NLS-1$
+
+ // create a new Feature reference to be added to the site
+ SiteFeatureReference ref = new SiteFeatureReference();
+ ref.setSite(getSite());
+ File file = null;
+
+ try {
+ file = new File(getFeaturePath());
+ ref.setURL(file.toURL());
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteFileContentConsumer_UnableToCreateURLForFile, (new String[] { file.getAbsolutePath() })), e);
+ }
+
+ //rename file back
+ if (newPath != null) {
+ ErrorRecoveryLog.getLog().appendPath(ErrorRecoveryLog.RENAME_ENTRY, newPath);
+ boolean sucess = false;
+ File fileToRename = new File(newPath);
+ if (fileToRename.exists()) {
+ File renamedFile = new File(oldPath);
+ if (renamedFile.exists()) {
+ UpdateManagerUtils.removeFromFileSystem(renamedFile);
+ UpdateCore.warn("Removing already existing file:" + oldPath); //$NON-NLS-1$
+ }
+ sucess = fileToRename.renameTo(renamedFile);
+ }
+ if (!sucess) {
+ String msg = NLS.bind(Messages.ContentConsumer_UnableToRename, (new String[] { newPath, oldPath }));
+ throw Utilities.newCoreException(msg, new Exception(msg));
+ }
+ }
+
+ // close plugin and non plugin content consumer
+ if (contentConsumers != null) {
+ Iterator iter = contentConsumers.iterator();
+ while (iter.hasNext()) {
+ ContentConsumer element = (ContentConsumer) iter.next();
+ element.close();
+ }
+ }
+ contentConsumers = null;
+
+ if (ref != null) {
+ // the feature MUST have renamed the plugins at that point
+ // (by closing the PluginContentConsumer)
+ commitPlugins(ref);
+ ref.markReadOnly();
+ }
+
+ closed = true;
+ return ref;
+ }
+
+ /*
+ * @see ISiteContentConsumer#abort()
+ */
+ public void abort() throws CoreException {
+
+ if (closed) {
+ UpdateCore.warn("Attempt to abort a closed SiteFileContentConsumer", new Exception()); //$NON-NLS-1$
+ return;
+ }
+
+ //abort all plugins content consumer opened
+ if (contentConsumers != null) {
+ Iterator iter = contentConsumers.iterator();
+ while (iter.hasNext()) {
+ Object element = iter.next();
+ if (element instanceof SiteFilePluginContentConsumer) {
+ ((SiteFilePluginContentConsumer)element).abort();
+ } else if (element instanceof SiteFilePackedPluginContentConsumer){
+ ((SiteFilePackedPluginContentConsumer)element).abort();
+ }
+
+ }
+ }
+ contentConsumers = null;
+ boolean sucess = true;
+
+ //Remove feature.xml first if it exists
+ if (oldPath != null) {
+ ErrorRecoveryLog.getLog().appendPath(ErrorRecoveryLog.DELETE_ENTRY, oldPath);
+ File fileToDelete = new File(oldPath);
+ if (fileToDelete.exists()) {
+ sucess = fileToDelete.delete();
+ }
+ }
+
+ if (!sucess) {
+ String msg = NLS.bind(Messages.SiteFileContentConsumer_unableToDelete, (new String[] { oldPath }));
+ UpdateCore.log(msg, null);
+ } else {
+ // remove the feature files;
+ Iterator iter = installedFiles.iterator();
+ File featureFile = null;
+ while (iter.hasNext()) {
+ String path = (String) iter.next();
+ featureFile = new File(path);
+ UpdateManagerUtils.removeFromFileSystem(featureFile);
+ }
+
+ // remove the feature directory if empty
+ String featurePath = getFeaturePath();
+ UpdateManagerUtils.removeEmptyDirectoriesFromFileSystem(new File(featurePath));
+ }
+ closed = true;
+ return;
+ }
+
+ /*
+ * commit the plugins installed as archive on the site
+ * (creates the map between the plugin id and the location of the plugin)
+ */
+ private void commitPlugins(IFeatureReference localFeatureReference) throws CoreException {
+
+ // get the feature
+ ((SiteFile) getSite()).addFeatureReferenceModel((SiteFeatureReferenceModel) localFeatureReference);
+ IFeature localFeature = null;
+ try {
+ localFeature = localFeatureReference.getFeature(null);
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ return;
+ }
+
+ if (localFeature == null)
+ return;
+
+ // add the installed plugins directories as archives entry
+ ArchiveReferenceModel archive = null;
+ IPluginEntry[] pluginEntries = localFeature.getPluginEntries();
+ for (int i = 0; i < pluginEntries.length; i++) {
+ String versionId = pluginEntries[i].getVersionedIdentifier().toString();
+ String pluginID = Site.DEFAULT_PLUGIN_PATH + versionId + FeatureContentProvider.JAR_EXTENSION;
+ archive = archiveFactory.createArchiveReferenceModel();
+ archive.setPath(pluginID);
+ try {
+ URL url = null;
+ if (pluginEntries[i] instanceof PluginEntryModel
+ && !((PluginEntryModel) pluginEntries[i]).isUnpack()) {
+ url = new URL(getSite().getURL(), Site.DEFAULT_PLUGIN_PATH + versionId + ".jar"); //$NON-NLS-1$
+ } else {
+ url = new URL(getSite().getURL(), Site.DEFAULT_PLUGIN_PATH + versionId + File.separator);
+ }
+ archive.setURLString(url.toExternalForm());
+ archive.resolve(url, null);
+ ((SiteFile) getSite()).addArchiveReferenceModel(archive);
+ } catch (MalformedURLException e) {
+
+ String urlString = (getSite().getURL() != null) ? getSite().getURL().toExternalForm() : ""; //$NON-NLS-1$
+ urlString += Site.DEFAULT_PLUGIN_PATH + pluginEntries[i].toString();
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteFile_UnableToCreateURL, (new String[] { urlString })), e);
+ }
+ }
+ return;
+ }
+
+ /*
+ * Adds a SiteFilePluginContentConsumer to the list
+ */
+ private void addContentConsumers(ContentConsumer cons) {
+ if (contentConsumers == null)
+ contentConsumers = new ArrayList();
+ contentConsumers.add(cons);
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFileContentProvider.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFileContentProvider.java
new file mode 100644
index 0000000..09ce8c2
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFileContentProvider.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+import java.net.URL;
+
+import org.eclipse.update.core.SiteContentProvider;
+
+/**
+ * Site on the File System
+ */
+public class SiteFileContentProvider extends SiteContentProvider {
+
+ public static final String SITE_TYPE = "org.eclipse.update.core.file"; //$NON-NLS-1$
+
+ /**
+ * Constructor for FileSite
+ */
+ public SiteFileContentProvider(URL url) {
+ super(url);
+ }
+}
+
+
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFileFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFileFactory.java
new file mode 100644
index 0000000..24dc5ca
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFileFactory.java
@@ -0,0 +1,446 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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.update.internal.core;
+
+import org.eclipse.update.core.FeatureContentProvider;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.BaseSiteFactory;
+import org.eclipse.update.core.ContentReference;
+import org.eclipse.update.core.Feature;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.JarContentReference;
+import org.eclipse.update.core.PluginEntry;
+import org.eclipse.update.core.Site;
+import org.eclipse.update.core.SiteContentProvider;
+import org.eclipse.update.core.SiteFeatureReferenceModel;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.core.model.ArchiveReferenceModel;
+import org.eclipse.update.core.model.InvalidSiteTypeException;
+import org.eclipse.update.core.model.SiteModel;
+import org.eclipse.update.core.model.SiteModelFactory;
+import org.eclipse.update.internal.model.BundleManifest;
+import org.eclipse.update.internal.model.DefaultPluginParser;
+import org.xml.sax.SAXException;
+
+public class SiteFileFactory extends BaseSiteFactory {
+
+ // private when parsing file system
+ private SiteFile site;
+
+ /*
+ * @see ISiteFactory#createSite(URL,boolean)
+ */
+ public ISite createSite(URL url) throws CoreException, InvalidSiteTypeException {
+
+ Site site = null;
+ InputStream siteStream = null;
+ SiteModelFactory factory = this;
+
+ try {
+ // if url points to a directory
+ // attempt to parse site.xml
+ String path = url.getFile();
+ File siteLocation = new File(path);
+ if (siteLocation.isDirectory()) {
+ url = siteLocation.toURL();
+ File siteXMLFile = new File(siteLocation, Site.SITE_XML);
+ if (siteXMLFile.exists()) {
+ siteStream = new FileInputStream(siteXMLFile);
+ site = (Site) factory.parseSite(siteStream);
+ } else {
+ // parse siteLocation
+ site = parseSite(siteLocation);
+ }
+ } else {
+ // we are not pointing to a directory
+ // attempt to parse the file
+ try {
+ URL resolvedURL = URLEncoder.encode(url);
+ siteStream = openStream(resolvedURL);
+ site = (Site) factory.parseSite(siteStream);
+ } catch (IOException e) {
+
+ // attempt to parse parent directory
+ File file = new File(url.getFile());
+ File parentDirectory = file.getParentFile();
+
+ // do not create directory if it doesn't exist [18318]
+ // instead hrow error
+ if (parentDirectory != null && !parentDirectory.exists())
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_DirectoryDoesNotExist, (new String[] {file.getAbsolutePath()})), null);
+
+ if (parentDirectory == null || !parentDirectory.isDirectory())
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_UnableToObtainParentDirectory, (new String[] {file.getAbsolutePath()})), null);
+
+ site = parseSite(parentDirectory);
+
+ }
+ }
+
+ SiteContentProvider contentProvider = new SiteFileContentProvider(url);
+ site.setSiteContentProvider(contentProvider);
+ contentProvider.setSite(site);
+ site.resolve(url, url);
+
+ // Do not set read only as may install in it
+ //site.markReadOnly();
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_UnableToCreateURL, (new String[] {url == null ? "" : url.toExternalForm()})), e); //$NON-NLS-1$
+ } catch (IOException e) {
+ throw Utilities.newCoreException(Messages.SiteFileFactory_UnableToAccessSite, ISite.SITE_ACCESS_EXCEPTION, e);
+ } finally {
+ try {
+ if (siteStream != null)
+ siteStream.close();
+ } catch (IOException e) {
+ }
+ }
+ return site;
+ }
+
+ /**
+ * Method parseSite.
+ */
+ private Site parseSite(File directory) throws CoreException {
+
+ this.site = (SiteFile) createSiteMapModel();
+
+ if (!directory.exists())
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_FileDoesNotExist, (new String[] {directory.getAbsolutePath()})), null);
+
+ File pluginPath = new File(directory, Site.DEFAULT_PLUGIN_PATH);
+
+ //PACKAGED
+ try {
+ parsePackagedFeature(directory); // in case it contains JAR files
+ } catch (EmptyDirectoryException ede) {
+ UpdateCore.log(ede.getStatus());
+ }
+
+ try {
+ parsePackagedPlugins(pluginPath);
+ } catch (EmptyDirectoryException ede) {
+ UpdateCore.log(ede.getStatus());
+ }
+
+ // INSTALLED
+ try {
+ parseInstalledFeature(directory);
+ } catch (EmptyDirectoryException ede) {
+ UpdateCore.log(ede.getStatus());
+ }
+
+ try {
+ parseInstalledPlugins(pluginPath);
+ } catch (EmptyDirectoryException ede) {
+ UpdateCore.log(ede.getStatus());
+ }
+
+ return site;
+
+ }
+
+ /**
+ * Method parseFeature.
+ * @throws CoreException
+ */
+ private void parseInstalledFeature(File directory) throws CoreException {
+
+ File featureDir = new File(directory, Site.DEFAULT_INSTALLED_FEATURE_PATH);
+ if (featureDir.exists()) {
+ String[] dir;
+ SiteFeatureReferenceModel featureRef;
+ URL featureURL;
+ File currentFeatureDir;
+ String newFilePath = null;
+
+ try {
+ // handle the installed featuresConfigured under featuresConfigured subdirectory
+ dir = featureDir.list();
+ if (dir == null) {
+ throw new EmptyDirectoryException(new Status(IStatus.WARNING, UpdateCore.getPlugin().getBundle().getSymbolicName(), IStatus.OK, directory.getName() + File.separator + directory.getName() + "directory is empty", null)); //$NON-NLS-1$
+ }
+ for (int index = 0; index < dir.length; index++) {
+
+ // the URL must ends with '/' for the bundle to be resolved
+ newFilePath = dir[index] + (dir[index].endsWith("/") ? "/" : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ currentFeatureDir = new File(featureDir, newFilePath);
+ // check if feature.xml exists
+ File featureXMLFile = new File(currentFeatureDir, Feature.FEATURE_XML);
+ if (!featureXMLFile.exists()) {
+ UpdateCore.warn("Unable to find feature.xml in directory:" + currentFeatureDir); //$NON-NLS-1$
+ } else {
+ // PERF: remove code
+ //SiteFileFactory archiveFactory = new SiteFileFactory();
+ featureURL = currentFeatureDir.toURL();
+ featureRef = createFeatureReferenceModel();
+ featureRef.setSiteModel(site);
+ featureRef.setURLString(featureURL.toExternalForm());
+ featureRef.setType(ISite.DEFAULT_INSTALLED_FEATURE_TYPE);
+ ((Site) site).addFeatureReferenceModel(featureRef);
+ }
+ }
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_UnableToCreateURLForFile, (new String[] {newFilePath})), e);
+ }
+ }
+ }
+
+ /**
+ * Method parseFeature.
+ * @throws CoreException
+ */
+ private void parsePackagedFeature(File directory) throws CoreException {
+
+ // FEATURES
+ File featureDir = new File(directory, Site.DEFAULT_FEATURE_PATH);
+ if (featureDir.exists()) {
+ String[] dir;
+ SiteFeatureReferenceModel featureRef;
+ URL featureURL;
+ File currentFeatureFile;
+ String newFilePath = null;
+
+ try {
+ // only list JAR files
+ dir = featureDir.list(FeaturePackagedContentProvider.filter);
+ if (dir == null) {
+ throw new EmptyDirectoryException(new Status(IStatus.WARNING, UpdateCore.getPlugin().getBundle().getSymbolicName(), IStatus.OK, directory.getName() + File.separator + directory.getName() + "directory is empty", null)); //$NON-NLS-1$
+ }
+
+ for (int index = 0; index < dir.length; index++) {
+
+ // check if the JAR file contains a feature.xml
+ currentFeatureFile = new File(featureDir, dir[index]);
+ JarContentReference ref = new JarContentReference("", currentFeatureFile); //$NON-NLS-1$
+ ContentReference result = null;
+ try {
+ result = ref.peek(Feature.FEATURE_XML, null, null);
+ } catch (IOException e) {
+ UpdateCore.warn("Exception retrieving feature.xml in file:" + currentFeatureFile, e); //$NON-NLS-1$
+ }
+ if (result == null) {
+ UpdateCore.warn("Unable to find feature.xml in file:" + currentFeatureFile); //$NON-NLS-1$
+ } else {
+ featureURL = currentFeatureFile.toURL();
+ // PERF: remove code
+ //SiteFileFactory archiveFactory = new SiteFileFactory();
+ featureRef = createFeatureReferenceModel();
+ featureRef.setSiteModel(site);
+ featureRef.setURLString(featureURL.toExternalForm());
+ featureRef.setType(ISite.DEFAULT_PACKAGED_FEATURE_TYPE);
+ site.addFeatureReferenceModel(featureRef);
+ }
+ }
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_UnableToCreateURLForFile, (new String[] {newFilePath})), e);
+ }
+ }
+ }
+
+ /**
+ * Method parsePlugins.
+ *
+ * look into each plugin/fragment directory, crack the plugin.xml open (or
+ * fragment.xml ???) get id and version, calculate URL...
+ *
+ * @throws CoreException
+ */
+ private void parseInstalledPlugins(File pluginsDir) throws CoreException {
+ if (!pluginsDir.exists() || !pluginsDir.isDirectory()) {
+ return;
+ }
+ File[] dirs = pluginsDir.listFiles(new FileFilter() {
+ public boolean accept(File f) {
+ return f.isDirectory();
+ }
+ });
+ DefaultPluginParser parser = new DefaultPluginParser();
+
+ if (dirs == null) {
+ throw new EmptyDirectoryException(new Status(IStatus.WARNING, UpdateCore.getPlugin().getBundle().getSymbolicName(), IStatus.OK, pluginsDir.getName() + File.separator + pluginsDir.getName() + "directory is empty", null)); //$NON-NLS-1$
+ }
+ for (int i = 0; i < dirs.length; i++) {
+ File pluginFile = new File(dirs[i], "META-INF/MANIFEST.MF"); //$NON-NLS-1$
+ InputStream in = null;
+ try {
+ BundleManifest bundleManifest = new BundleManifest(pluginFile);
+ if (bundleManifest.exists()) {
+ PluginEntry entry = bundleManifest.getPluginEntry();
+ addParsedPlugin(entry, dirs[i]);
+ } else {
+ if (!(pluginFile = new File(dirs[i], "plugin.xml")) //$NON-NLS-1$
+ .exists()) {
+ pluginFile = new File(dirs[i], "fragment.xml"); //$NON-NLS-1$
+ }
+ if (pluginFile != null && pluginFile.exists() && !pluginFile.isDirectory()) {
+ in = new FileInputStream(pluginFile);
+ PluginEntry entry = parser.parse(in);
+ addParsedPlugin(entry, dirs[i]);
+ }
+ }
+ } catch (IOException e) {
+ String pluginFileString = (pluginFile == null) ? null : pluginFile.getAbsolutePath();
+ UpdateCore.log(Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_ErrorAccessing, (new String[] {pluginFileString})), e));
+ } catch (SAXException e) {
+ String pluginFileString = (pluginFile == null) ? null : pluginFile.getAbsolutePath();
+ UpdateCore.log(Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_ErrorParsingFile, (new String[] {pluginFileString})), e));
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * transform each Plugin and Fragment into an ArchiveReferenceModel
+ * and a PluginEntry for the Site
+ */
+ // PERF: removed intermediate Plugin object
+ private void addParsedPlugin(PluginEntry entry, File file) throws CoreException {
+
+ String location = null;
+ try {
+ if (entry != null) {
+
+ // create the plugin Entry
+ ((Site) site).addPluginEntry(entry);
+
+ // Create the Site mapping ArchiveRef->PluginEntry
+ // the id of the archiveRef is plugins\<pluginid>_<ver>.jar as per the specs
+ // PERF: remove code
+ //SiteFileFactory archiveFactory = new SiteFileFactory();
+ ArchiveReferenceModel archive = createArchiveReferenceModel();
+ String id = (entry.getVersionedIdentifier().toString());
+ String pluginID = Site.DEFAULT_PLUGIN_PATH + id + FeatureContentProvider.JAR_EXTENSION;
+ archive.setPath(pluginID);
+ location = file.toURL().toExternalForm();
+ archive.setURLString(location);
+ ((Site) site).addArchiveReferenceModel(archive);
+
+ // TRACE
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
+ UpdateCore.debug("Added archive to site:" + pluginID + " pointing to: " + location); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_UnableToCreateURLForFile, (new String[] {location})), e);
+ }
+ }
+
+ /**
+ *
+ */
+ private void parsePackagedPlugins(File pluginDir) throws CoreException {
+ if (!pluginDir.exists()) {
+ return;
+ }
+ String[] dir = pluginDir.list(FeaturePackagedContentProvider.filter);
+
+ if (dir == null) {
+ throw new EmptyDirectoryException(new Status(IStatus.WARNING, UpdateCore.getPlugin().getBundle().getSymbolicName(), IStatus.OK, pluginDir.getName() + File.separator + pluginDir.getName() + "directory is empty", null)); //$NON-NLS-1$
+ }
+ for (int i = 0; i < dir.length; i++) {
+ ContentReference ref = null;
+ String refString = null;
+ InputStream in = null;
+ JarContentReference jarReference = null;
+ try {
+ File file = new File(pluginDir, dir[i]);
+ jarReference = new JarContentReference(null, file);
+ ref = jarReference.peek("META-INF/MANIFEST.MF", null, null); //$NON-NLS-1$
+ if (ref != null) {
+ in = ref.getInputStream();
+ BundleManifest manifest = new BundleManifest(in);
+ if (manifest.exists()) {
+
+ addParsedPlugin(manifest.getPluginEntry(), file);
+ continue;
+ }
+ }
+ ref = jarReference.peek("plugin.xml", null, null);//$NON-NLS-1$
+ if (ref == null) {
+ ref = jarReference.peek("fragment.xml", null, null); //$NON-NLS-1$
+ }
+ if (ref != null) {
+ in = ref.getInputStream();
+ PluginEntry entry = new DefaultPluginParser().parse(in);
+ addParsedPlugin(entry, file);
+ }
+ } catch (Exception e) {
+ try {
+ refString = (ref == null) ? null : ref.asURL().toExternalForm();
+ } catch (IOException ioe) {
+ }
+
+ String message;
+
+ if (e instanceof IOException) {
+ message = NLS.bind(Messages.SiteFileFactory_ErrorAccessing, (new String[] {refString}));
+ } else if (e instanceof SAXException) {
+ message = NLS.bind(Messages.SiteFileFactory_ErrorParsingFile, (new String[] {refString}));
+ } else {
+ message = NLS.bind(Messages.SiteFileFactory_ErrorAccessing, (new String[] {refString}));
+ }// end if
+
+ // Log exception, but do not throw to caller.
+ // Continue with processing remaining plug-ins
+ UpdateCore.log(message, e);
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException ce) {
+ }
+ }
+ if (jarReference != null) {
+ try {
+ jarReference.closeArchive();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * @see SiteModelFactory#createSiteMapModel()
+ */
+ public SiteModel createSiteMapModel() {
+ return new SiteFile();
+ }
+
+ /*
+ * @see SiteModelFactory#canParseSiteType(String)
+ */
+ public boolean canParseSiteType(String type) {
+ return (super.canParseSiteType(type) || SiteFileContentProvider.SITE_TYPE.equalsIgnoreCase(type));
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFileNonPluginContentConsumer.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFileNonPluginContentConsumer.java
new file mode 100644
index 0000000..7dbfd58
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFileNonPluginContentConsumer.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+import java.io.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+
+/**
+ * Plugin Content Consumer on a Site
+ */
+public class SiteFileNonPluginContentConsumer extends ContentConsumer {
+
+ private String path;
+ private boolean closed = false;
+
+ /*
+ * Constructor
+ */
+ public SiteFileNonPluginContentConsumer(String featurePath) {
+ this.path = featurePath;
+ }
+
+ /*
+ * @see ISiteContentConsumer#store(ContentReference, IProgressMonitor)
+ */
+ public void store(ContentReference contentReference, IProgressMonitor monitor) throws CoreException {
+
+ if (closed) {
+ UpdateCore.warn("Attempt to store in a closed SiteFileNonPluginContentConsumer", new Exception()); //$NON-NLS-1$
+ return;
+ }
+
+ InputStream inStream = null;
+ String featurePath = path;
+ String contentKey = contentReference.getIdentifier();
+ featurePath += contentKey;
+ try {
+ inStream = contentReference.getInputStream();
+ UpdateManagerUtils.copyToLocal(inStream, featurePath, null);
+ UpdateManagerUtils.checkPermissions(contentReference, featurePath); // 20305
+ } catch (IOException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.GlobalConsumer_ErrorCreatingFile, (new String[] { featurePath })), e);
+ } finally {
+ if (inStream != null) {
+ try {
+ // close stream
+ inStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ }
+
+ /*
+ * @see ISiteContentConsumer#close()
+ */
+ public void close() {
+ if (closed) {
+ UpdateCore.warn("Attempt to close a closed SiteFileNonPluginContentConsumer", new Exception()); //$NON-NLS-1$
+ return;
+ }
+ closed = true;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFilePackedPluginContentConsumer.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFilePackedPluginContentConsumer.java
new file mode 100644
index 0000000..bf65225
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFilePackedPluginContentConsumer.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+import java.io.*;
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+
+/**
+ * Plugin Content Consumer on a Site
+ * for a plugin that will run from a jar
+ */
+public class SiteFilePackedPluginContentConsumer extends ContentConsumer {
+
+ private IPluginEntry pluginEntry;
+ private ISite site;
+ private boolean closed = false;
+ private String jarPath;
+ private String tempPath;
+
+ /*
+ * Constructor
+ */
+ public SiteFilePackedPluginContentConsumer(IPluginEntry pluginEntry, ISite site) {
+ this.pluginEntry = pluginEntry;
+ this.site = site;
+ }
+
+ /*
+ * @see ISiteContentConsumer#store(ContentReference, IProgressMonitor)
+ */
+ public void store(ContentReference contentReference, IProgressMonitor monitor) throws CoreException {
+ InputStream inStream = null;
+
+ if (closed) {
+ UpdateCore.warn("Attempt to store in a closed SiteFilePluginContentConsumer", new Exception()); //$NON-NLS-1$
+ return;
+ }
+
+ try {
+ URL newURL = new URL(site.getURL(), Site.DEFAULT_PLUGIN_PATH + pluginEntry.getVersionedIdentifier().toString() + ".jar"); //$NON-NLS-1$
+ inStream = contentReference.getInputStream();
+ jarPath = newURL.getFile().replace(File.separatorChar, '/');
+ File jarFile = new File(jarPath);
+ if (jarFile.exists()) {
+ throw Utilities.newCoreException(NLS.bind(Messages.UpdateManagerUtils_FileAlreadyExists, (new Object[] { jarFile })), null);
+ }
+ // error recovery
+ tempPath= ErrorRecoveryLog.getLocalRandomIdentifier(jarPath+".tmp"); //$NON-NLS-1$
+ ErrorRecoveryLog.getLog().appendPath(ErrorRecoveryLog.BUNDLE_JAR_ENTRY, tempPath);
+ //
+ UpdateManagerUtils.copyToLocal(inStream, tempPath, null);
+ } catch (IOException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.GlobalConsumer_ErrorCreatingFile, (new String[] { tempPath })), e);
+ } finally {
+ if (inStream != null) {
+ try {
+ // close stream
+ inStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ /*
+ * @see ISiteContentConsumer#close()
+ */
+ public void close() throws CoreException {
+
+ if (closed) {
+ UpdateCore.warn("Attempt to close a closed SiteFilePluginContentConsumer", new Exception()); //$NON-NLS-1$
+ return;
+ }
+
+ if (tempPath != null) {
+ // rename file
+ ErrorRecoveryLog.getLog().appendPath(ErrorRecoveryLog.RENAME_ENTRY, tempPath);
+ File fileToRename = new File(tempPath);
+ boolean sucess = false;
+ if (fileToRename.exists()) {
+ File renamedFile = new File(jarPath);
+ sucess = fileToRename.renameTo(renamedFile);
+ }
+ if (!sucess) {
+ String msg = NLS.bind(Messages.ContentConsumer_UnableToRename, (new String[] { tempPath, jarPath }));
+ throw Utilities.newCoreException(msg, new Exception(msg));
+ }
+ }
+
+ if (site instanceof SiteFile)
+ ((SiteFile) site).addPluginEntry(pluginEntry);
+ closed = true;
+ }
+
+ /*
+ *
+ */
+ public void abort() throws CoreException {
+
+ if (closed) {
+ UpdateCore.warn("Attempt to abort a closed SiteFilePluginContentConsumer", new Exception()); //$NON-NLS-1$
+ return;
+ }
+
+ boolean sucess = true;
+
+ // delete plugin.jar
+ if (jarPath != null) {
+ ErrorRecoveryLog.getLog().appendPath(ErrorRecoveryLog.DELETE_ENTRY, jarPath);
+ File fileToRemove = new File(jarPath);
+
+ if (fileToRemove.exists()) {
+ sucess = fileToRemove.delete();
+ }
+ }
+
+ if (!sucess) {
+ String msg = NLS.bind(Messages.SiteFilePackedPluginContentConsumer_unableToDelete, (new String[] { jarPath }));
+ UpdateCore.log(msg, null);
+ }
+ closed = true;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFilePluginContentConsumer.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFilePluginContentConsumer.java
new file mode 100644
index 0000000..3b3d047
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFilePluginContentConsumer.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+import java.io.*;
+import java.net.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+
+/**
+ * Plugin Content Consumer on a Site
+ */
+public class SiteFilePluginContentConsumer extends ContentConsumer {
+
+ private IPluginEntry pluginEntry;
+ private ISite site;
+ private boolean closed = false;
+
+ // recovery
+ // temporary name to original name map
+ private Map renames = new HashMap(2);
+
+ // for abort
+ private List /*of path as String */
+ installedFiles;
+
+ /*
+ * Constructor
+ */
+ public SiteFilePluginContentConsumer(IPluginEntry pluginEntry, ISite site) {
+ this.pluginEntry = pluginEntry;
+ this.site = site;
+ installedFiles = new ArrayList();
+ }
+
+ /*
+ * @see ISiteContentConsumer#store(ContentReference, IProgressMonitor)
+ */
+ public void store(ContentReference contentReference, IProgressMonitor monitor) throws CoreException {
+ InputStream inStream = null;
+ String pluginPath = null;
+
+ if (closed) {
+ UpdateCore.warn("Attempt to store in a closed SiteFilePluginContentConsumer", new Exception()); //$NON-NLS-1$
+ return;
+ }
+
+ try {
+ URL newURL = new URL(site.getURL(), Site.DEFAULT_PLUGIN_PATH + pluginEntry.getVersionedIdentifier().toString());
+ pluginPath = newURL.getFile();
+ String contentKey = contentReference.getIdentifier();
+ inStream = contentReference.getInputStream();
+ pluginPath += pluginPath.endsWith(File.separator) ? contentKey : File.separator + contentKey;
+
+ // error recovery
+ String logEntry=null;
+ if ("plugin.xml".equals(contentKey)) { //$NON-NLS-1$
+ logEntry=ErrorRecoveryLog.PLUGIN_ENTRY;
+ } else if ("fragment.xml".equals(contentKey)) { //$NON-NLS-1$
+ logEntry=ErrorRecoveryLog.FRAGMENT_ENTRY;
+ } else if ("META-INF/MANIFEST.MF".equals(contentKey)) { //$NON-NLS-1$
+ logEntry=ErrorRecoveryLog.BUNDLE_MANIFEST_ENTRY;
+ }
+ if (logEntry!=null) {
+ String originalName = pluginPath.replace(File.separatorChar, '/');
+ File localFile = new File(originalName);
+ if (localFile.exists()) {
+ throw Utilities.newCoreException(NLS.bind(Messages.UpdateManagerUtils_FileAlreadyExists, (new Object[] { localFile })), null);
+ }
+ pluginPath = ErrorRecoveryLog.getLocalRandomIdentifier(pluginPath);
+ renames.put(pluginPath, originalName);
+ ErrorRecoveryLog.getLog().appendPath(logEntry, pluginPath);
+ }
+ //
+ UpdateManagerUtils.copyToLocal(inStream, pluginPath, null);
+ UpdateManagerUtils.checkPermissions(contentReference, pluginPath); // 20305
+ installedFiles.add(pluginPath);
+ } catch (IOException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.GlobalConsumer_ErrorCreatingFile, (new String[] { pluginPath })), e);
+ } finally {
+ if (inStream != null) {
+ try {
+ // close stream
+ inStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ /*
+ * @see ISiteContentConsumer#close()
+ */
+ public void close() throws CoreException {
+
+ if (closed) {
+ UpdateCore.warn("Attempt to close a closed SiteFilePluginContentConsumer", new Exception()); //$NON-NLS-1$
+ return;
+ }
+
+ for(Iterator it = renames.entrySet().iterator(); it.hasNext();){
+ // rename file
+ Map.Entry entry = (Map.Entry)it.next();
+ String temporary = (String) entry.getKey();
+ String original = (String) entry.getValue();
+ ErrorRecoveryLog.getLog().appendPath(ErrorRecoveryLog.RENAME_ENTRY, temporary);
+ File fileToRename = new File(temporary);
+ boolean sucess = false;
+ if (fileToRename.exists()) {
+ File renamedFile = new File(original);
+ sucess = fileToRename.renameTo(renamedFile);
+ }
+ if (!sucess) {
+ String msg = NLS.bind(Messages.ContentConsumer_UnableToRename, (new String[] { temporary, original }));
+ throw Utilities.newCoreException(msg, new Exception(msg));
+ }
+ }
+
+ if (site instanceof SiteFile)
+ ((SiteFile) site).addPluginEntry(pluginEntry);
+ closed = true;
+ }
+
+ /*
+ *
+ */
+ public void abort() throws CoreException {
+
+ if (closed) {
+ UpdateCore.warn("Attempt to abort a closed SiteFilePluginContentConsumer", new Exception()); //$NON-NLS-1$
+ return;
+ }
+
+ boolean success = true;
+ InstallRegistry.unregisterPlugin(pluginEntry);
+
+ // delete plugin manifests first
+ for(Iterator it = renames.values().iterator(); it.hasNext();){
+ String originalName = (String) it.next();
+
+ ErrorRecoveryLog.getLog().appendPath(ErrorRecoveryLog.DELETE_ENTRY, originalName);
+ File fileToRemove = new File(originalName);
+ if (fileToRemove.exists()) {
+ if(!fileToRemove.delete()){
+ String msg = NLS.bind(Messages.SiteFilePluginContentConsumer_unableToDelete, (new String[] { originalName }));
+ UpdateCore.log(msg, null);
+ success = false;
+ }
+ }
+ }
+
+ if (success) {
+ // remove the plugin files;
+ Iterator iter = installedFiles.iterator();
+ File featureFile = null;
+ while (iter.hasNext()) {
+ String path = (String) iter.next();
+ featureFile = new File(path);
+ UpdateManagerUtils.removeFromFileSystem(featureFile);
+ }
+
+ // remove the plugin directory if empty
+ try {
+ URL newURL = new URL(site.getURL(), Site.DEFAULT_PLUGIN_PATH + pluginEntry.getVersionedIdentifier().toString());
+ String pluginPath = newURL.getFile();
+ UpdateManagerUtils.removeEmptyDirectoriesFromFileSystem(new File(pluginPath));
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(e.getMessage(), e);
+ }
+ }
+ closed = true;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteReconciler.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteReconciler.java
new file mode 100644
index 0000000..7fdb7ff
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteReconciler.java
@@ -0,0 +1,347 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.core;
+
+import java.util.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.core.*;
+import org.eclipse.update.core.model.ModelObject;
+
+/**
+ * This class manages the reconciliation.
+ */
+
+public class SiteReconciler extends ModelObject {
+
+ private SiteReconciler(LocalSite siteLocal) {
+ //never instantiated
+ }
+
+ /**
+ * Validate the list of configured features eliminating extra
+ * entries (if possible). Make sure we do not leave configured
+ * nested features with "holes" (ie. unconfigured children)
+ */
+ public static void checkConfiguredFeatures(IConfiguredSite configuredSite) {
+
+ // Note: if we hit errors in the various computation
+ // methods and throw a CoreException, we will not catch it
+ // in this method. Consequently we will not attempt to
+ // unconfigure any "extra" features because we would
+ // likely get it wrong. The platform will run with extra features
+ // configured. The runtime will eliminate extra plugins based
+ // on runtime binding rules.
+
+ // determine "proposed" list of configured features
+ ConfiguredSite cSite = (ConfiguredSite) configuredSite;
+ // debug
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) {
+ UpdateCore.debug("Validate configuration of site " + cSite.getSite().getURL()); //$NON-NLS-1$
+ }
+ IFeatureReference[] configuredRefs = cSite.getConfiguredFeatures();
+ ArrayList allPossibleConfiguredFeatures = new ArrayList();
+ for (int i = 0; i < configuredRefs.length; i++) {
+ try {
+ IFeature feature = configuredRefs[i].getFeature(null);
+ allPossibleConfiguredFeatures.add(feature);
+ // debug
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) {
+ UpdateCore.debug(" configured feature " + feature.getVersionedIdentifier().toString()); //$NON-NLS-1$
+ }
+ } catch (CoreException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+ }
+
+ // find top level features
+ ArrayList topFeatures = computeTopFeatures(allPossibleConfiguredFeatures);
+
+ // find non efix top level features
+ ArrayList topNonEfixFeatures = getNonEfixFeatures(topFeatures);
+
+ // expand non efix top level features (compute full nesting structures).
+ ArrayList configuredFeatures = expandFeatures(topNonEfixFeatures, configuredSite);
+
+ // retrieve efixes that patch enable feature
+ // they must be kept enabled
+ if (topFeatures.size() != topNonEfixFeatures.size()) {
+ Map patches = getPatchesAsFeature(allPossibleConfiguredFeatures);
+ if (!patches.isEmpty()) {
+ // calculate efixes to enable
+ List efixesToEnable = getPatchesToEnable(patches, configuredFeatures);
+ // add efies to keep enable
+ //add them to the enable list
+ for (Iterator iter = efixesToEnable.iterator(); iter.hasNext();) {
+ IFeature element = (IFeature) iter.next();
+ ArrayList expandedEfix = new ArrayList();
+ expandEfixFeature(element, expandedEfix, configuredSite);
+ configuredFeatures.addAll(expandedEfix);
+ }
+ }
+ }
+
+ // compute extra features
+ ArrayList extras = diff(allPossibleConfiguredFeatures, configuredFeatures);
+
+ // unconfigure extra features
+ ConfigurationPolicy cPolicy = cSite.getConfigurationPolicy();
+ for (int i = 0; i < extras.size(); i++) {
+ IFeature feature = (IFeature) extras.get(i);
+ IFeatureReference ref = cSite.getSite().getFeatureReference(feature);
+ try {
+ cPolicy.unconfigure(ref, true, false);
+ // debug
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) {
+ UpdateCore.debug("Unconfiguring \"extra\" feature " + feature.getVersionedIdentifier().toString()); //$NON-NLS-1$
+ }
+ } catch (CoreException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /*
+ *
+ */
+ private static ArrayList computeTopFeatures(ArrayList features) {
+ /* map of Feature by VersionedIdentifier */
+ Map topFeatures = new HashMap(features.size());
+ // start with the features passed in
+ for (Iterator it = features.iterator(); it.hasNext();) {
+ IFeature f = ((IFeature) it.next());
+ topFeatures.put(f.getVersionedIdentifier(), f);
+ }
+ // remove all features that nest in some other feature
+ for (Iterator it = features.iterator(); it.hasNext();) {
+ try {
+ IIncludedFeatureReference[] children = ((IFeature) it.next()).getIncludedFeatureReferences();
+ for (int j = 0; j < children.length; j++) {
+ try {
+ topFeatures.remove(children[j].getVersionedIdentifier());
+ } catch (CoreException e1) {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_WARNINGS)
+ UpdateCore.warn("", e1); //$NON-NLS-1$
+ }
+ }
+ } catch (CoreException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+ }
+ ArrayList list = new ArrayList();
+ list.addAll(topFeatures.values());
+ // debug
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) {
+ UpdateCore.debug("Computed top-level features"); //$NON-NLS-1$
+ for (int i = 0; i < topFeatures.size(); i++) {
+ UpdateCore.debug(" " + ((IFeature) list.get(i)).getVersionedIdentifier().toString()); //$NON-NLS-1$
+ }
+ }
+ return list;
+ }
+
+ /*
+ *
+ */
+ private static ArrayList expandFeatures(ArrayList features, IConfiguredSite configuredSite) {
+ ArrayList result = new ArrayList();
+
+ // expand all top level features
+ for (int i = 0; i < features.size(); i++) {
+ expandFeature((IFeature) features.get(i), result, configuredSite);
+ }
+
+ return result;
+ }
+
+ /*
+ *
+ */
+ private static void expandFeature(IFeature feature, ArrayList features, IConfiguredSite configuredSite) {
+
+ // add feature
+ if (!features.contains(feature)) {
+ features.add(feature);
+ // debug
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) {
+ UpdateCore.debug("Retaining configured feature " + feature.getVersionedIdentifier().toString()); //$NON-NLS-1$
+ }
+ }
+
+ // add nested children to the list
+ IIncludedFeatureReference[] children = null;
+ try {
+ children = feature.getIncludedFeatureReferences();
+ } catch (CoreException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ return;
+ }
+
+ for (int j = 0; j < children.length; j++) {
+ IFeature child = null;
+ try {
+ child = children[j].getFeature(null);
+ } catch (CoreException e) {
+ if (!UpdateManagerUtils.isOptional(children[j]))
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ // 25202 do not return right now, the peer children may be ok
+ }
+ if (child != null)
+ expandFeature(child, features, configuredSite);
+ }
+ }
+
+ /*
+ *
+ */
+ private static ArrayList diff(ArrayList left, ArrayList right) {
+ ArrayList result = new ArrayList();
+
+ // determine difference (left "minus" right)
+ for (int i = 0; i < left.size(); i++) {
+ IFeature feature = (IFeature) left.get(i);
+ if (!right.contains(feature))
+ result.add(feature);
+ }
+ return result;
+ }
+
+ /*
+ * get the list of enabled patches
+ */
+ private static Map getPatchesAsFeature(ArrayList allConfiguredFeatures) {
+ // get all efixes and the associated patched features
+ Map patches = new HashMap();
+ if (allConfiguredFeatures != null) {
+ Iterator iter = allConfiguredFeatures.iterator();
+ while (iter.hasNext()) {
+ List patchedFeaturesID = new ArrayList();
+ IFeature element = (IFeature) iter.next();
+ // add the patched feature identifiers
+ for (int i = 0; i < element.getImports().length; i++) {
+ if (element.getImports()[i].isPatch()) {
+ VersionedIdentifier id = element.getImports()[i].getVersionedIdentifier();
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER)
+ UpdateCore.debug("Found patch " + element + " for feature identifier " + id); //$NON-NLS-1$ //$NON-NLS-2$
+ patchedFeaturesID.add(id);
+ }
+ }
+
+ if (!patchedFeaturesID.isEmpty()) {
+ patches.put(element, patchedFeaturesID);
+ }
+ }
+ }
+
+ return patches;
+ }
+
+ /*
+ * retruns the list of pathes-feature who patch enabled features
+ */
+ private static List getPatchesToEnable(Map efixes, ArrayList configuredFeatures) {
+
+ ArrayList enabledVersionedIdentifier = new ArrayList();
+ Iterator iter = configuredFeatures.iterator();
+ while (iter.hasNext()) {
+ IFeature element = (IFeature) iter.next();
+ enabledVersionedIdentifier.add(element.getVersionedIdentifier());
+ }
+
+ // loop through the patches
+ List result = new ArrayList();
+ iter = efixes.keySet().iterator();
+ while (iter.hasNext()) {
+ boolean toEnable = false;
+ IFeature efixFeature = (IFeature) iter.next();
+ List patchedFeatures = (List) efixes.get(efixFeature);
+ // loop through the 'patched features identifier' the for this patch
+ // see if it the patch patches at least one enable feature
+ Iterator patchedFeaturesIter = patchedFeatures.iterator();
+ while (patchedFeaturesIter.hasNext() && !toEnable) {
+ VersionedIdentifier patchedFeatureID = (VersionedIdentifier) patchedFeaturesIter.next();
+ if (enabledVersionedIdentifier.contains(patchedFeatureID)) {
+ toEnable = true;
+ }
+ }
+
+ if (!toEnable) {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER)
+ UpdateCore.debug("The Patch " + efixFeature + " does not patch any enabled features: it will be disabled"); //$NON-NLS-1$ //$NON-NLS-2$
+ } else {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER)
+ UpdateCore.debug("The patch " + efixFeature + " will be enabled."); //$NON-NLS-1$ //$NON-NLS-2$
+ result.add(efixFeature);
+ }
+ }
+ return result;
+ }
+
+ /*
+ * returns the feature that are not patches
+ */
+ private static ArrayList getNonEfixFeatures(ArrayList topFeatures) {
+ Map efixFeatures = getPatchesAsFeature(topFeatures);
+ Set keySet = efixFeatures.keySet();
+ if (keySet == null || keySet.isEmpty())
+ return topFeatures;
+
+ Iterator iter = topFeatures.iterator();
+ ArrayList result = new ArrayList();
+ while (iter.hasNext()) {
+ IFeature element = (IFeature) iter.next();
+ if (!keySet.contains(element)) {
+ result.add(element);
+ }
+ }
+ return result;
+ }
+
+ /*
+ * only enable non-efix children recursively
+ */
+ private static void expandEfixFeature(IFeature feature, ArrayList features, IConfiguredSite configuredSite) {
+
+ // add feature
+ if (!features.contains(feature)) {
+ features.add(feature);
+ // debug
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) {
+ UpdateCore.debug("Retaining configured feature " + feature.getVersionedIdentifier().toString()); //$NON-NLS-1$
+ }
+ }
+
+ // add nested children to the list
+ IIncludedFeatureReference[] children = null;
+ try {
+ children = feature.getIncludedFeatureReferences();
+ } catch (CoreException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ return;
+ }
+
+ for (int j = 0; j < children.length; j++) {
+ IFeature child = null;
+ try {
+ child = children[j].getFeature(null);
+ } catch (CoreException e) {
+ if (!children[j].isOptional())
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ // 25202 do not return right now, the peer children may be ok
+ }
+ if (child != null) {
+ if (!UpdateCore.isPatch(child))
+ expandEfixFeature(child, features, configuredSite);
+ }
+ }
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteStatusAnalyzer.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteStatusAnalyzer.java
new file mode 100644
index 0000000..fcdbb1d
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteStatusAnalyzer.java
@@ -0,0 +1,463 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.internal.core;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.configurator.ConfiguratorUtils;
+import org.eclipse.update.configurator.IPlatformConfiguration;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IFeatureReference;
+import org.eclipse.update.core.IImport;
+import org.eclipse.update.core.IPluginEntry;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.VersionedIdentifier;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+/**
+ * This class manages the configurations.
+ */
+
+public class SiteStatusAnalyzer {
+
+ private static final String SOURCE_BUNDLES_PATH = "org.eclipse.equinox.source/source.info"; //$NON-NLS-1$
+ private static final String ID = "org.eclipse.update.core"; //$NON-NLS-1$
+ private static List allConfiguredFeatures; /*VersionedIdentifier */
+ private LocalSite siteLocal;
+
+ // A list of versionedIdentifiers for source bundles; initialized on demand.
+ private List sourceBundles = null;
+
+ /**
+ *
+ */
+ public SiteStatusAnalyzer(LocalSite siteLocal) {
+ this.siteLocal = siteLocal;
+ }
+
+ /*
+ * check if the Plugins of the feature are on the plugin path
+ * If all the plugins are on the plugin path, and the version match and there is no other version -> HAPPY
+ * If all the plugins are on the plugin path, and the version match and there is other version -> AMBIGUOUS
+ * If some of the plugins are on the plugin path, but not all -> UNHAPPY
+ * Check on all ConfiguredSites
+ */
+ private IStatus getStatus(IFeature feature) {
+
+ // validate site
+ ISite featureSite = feature.getSite();
+ if (featureSite == null) {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION)
+ UpdateCore.debug("Cannot determine status of feature:" + feature.getLabel() + ". Site is NULL."); //$NON-NLS-1$ //$NON-NLS-2$
+ String msg = NLS.bind(Messages.SiteLocal_UnableToDetermineFeatureStatusSiteNull, (new Object[] {feature.getURL()}));
+ return createStatus(IStatus.ERROR, IFeature.STATUS_AMBIGUOUS, msg, null);
+ }
+
+ // validate configured site
+ ConfiguredSite cSite = (ConfiguredSite) featureSite.getCurrentConfiguredSite();
+ if (cSite == null) {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION)
+ UpdateCore.warn("Cannot determine status of feature: " + feature.getLabel() + ". Configured Site is NULL."); //$NON-NLS-1$ //$NON-NLS-2$
+ String msg = NLS.bind(Messages.SiteLocal_UnableToDetermineFeatureStatusConfiguredSiteNull, (new Object[] {feature.getURL()}));
+ return createStatus(IStatus.ERROR, IFeature.STATUS_AMBIGUOUS, msg, null);
+ }
+
+ // check if disable, if so return
+ IFeatureReference ref = cSite.getSite().getFeatureReference(feature);
+ if (ref != null) {
+ if (!cSite.getConfigurationPolicy().isConfigured(ref))
+ return createStatus(IStatus.OK, IFeature.STATUS_DISABLED, "", null); //$NON-NLS-1$
+ } else {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION)
+ UpdateCore.warn("Unable to find reference for feature " + feature + " in site " + cSite.getSite().getURL()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ // check if broken
+ IStatus status = cSite.getBrokenStatus(feature);
+ if (status.getSeverity() != IStatus.OK) {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION)
+ UpdateCore.debug("Feature broken:" + feature.getLabel() + ".Site:" + cSite.toString()); //$NON-NLS-1$ //$NON-NLS-2$
+ return status;
+ }
+
+ // check ambiguous against registry [17015]
+ IPluginEntry[] featuresEntries = feature.getPluginEntries();
+ return status(feature, featuresEntries);
+ }
+
+ /*
+ * check if the Plugins of the feature are on the plugin path
+ * If all the plugins are on the plugin path, and the version match and there is no other version -> HAPPY
+ * If all the plugins are on the plugin path, and the version match and there is other version -> AMBIGUOUS
+ * If some of the plugins are on the plugin path, but not all -> UNHAPPY
+ * Check on all ConfiguredSites
+ */
+ public IStatus getFeatureStatus(IFeature feature) throws CoreException {
+
+ IFeature childFeature = null;
+ IStatus childStatus;
+
+ IFeatureReference[] children = feature.getIncludedFeatureReferences();
+
+ // consider disable
+ // check the current feature
+ String msg = Messages.SiteLocal_FeatureDisable;
+ int code = IFeature.STATUS_DISABLED;
+ IStatus featureStatus = getStatus(feature);
+ MultiStatus multiTemp = new MultiStatus(featureStatus.getPlugin(), code, msg, null);
+ if (featureStatus.getSeverity() == IStatus.ERROR) {
+ if (featureStatus.isMultiStatus()) {
+ multiTemp.addAll(featureStatus);
+ } else {
+ multiTemp.add(featureStatus);
+ }
+ }
+ // preserve the worse code through the method (self assesment + children assessment)
+ if (featureStatus.getCode() > code)
+ code = featureStatus.getCode();
+
+ // do not check children if feature is disable
+ if (!(code == IFeature.STATUS_DISABLED)) {
+ for (int i = 0; i < children.length; i++) {
+ if (!UpdateManagerUtils.isOptional(children[i])) {
+ try {
+ childFeature = children[i].getFeature(null);
+ } catch (CoreException e) {
+ childFeature = null;
+ if (!UpdateManagerUtils.isOptional(children[i]))
+ UpdateCore.warn("Error retrieving feature:" + children[i]); //$NON-NLS-1$
+ }
+
+ if (childFeature == null) {
+ UpdateCore.warn("getFeatureStatus: Feature is null for:" + children[i]); //$NON-NLS-1$
+ // Unable to find children feature, broken
+ Object featureAsPrintableObject = children[i].getURL();
+ featureAsPrintableObject = children[i].getVersionedIdentifier();
+ String msg1 = NLS.bind(Messages.SiteLocal_NestedFeatureUnavailable, (new Object[] {featureAsPrintableObject}));
+ multiTemp.add(createStatus(IStatus.ERROR, IFeature.STATUS_UNHAPPY, msg1, null));
+ if (IFeature.STATUS_UNHAPPY > code)
+ code = IFeature.STATUS_UNHAPPY;
+ } else {
+ childStatus = getFeatureStatus(childFeature);
+ // do not add the status, add the children status as getFeatureStatus
+ // returns a multiStatus
+ if (childStatus.getCode() == IFeature.STATUS_DISABLED) {
+ VersionedIdentifier versionID = childFeature.getVersionedIdentifier();
+ String featureVer = (versionID == null) ? "" : versionID.getVersion().toString(); //$NON-NLS-1$
+ String msg1 = NLS.bind(Messages.SiteLocal_NestedFeatureDisable, (new String[] {childFeature.getLabel(), featureVer}));
+ multiTemp.add(createStatus(IStatus.ERROR, childStatus.getCode(), msg1, null));
+ if (IFeature.STATUS_UNHAPPY > code)
+ code = IFeature.STATUS_UNHAPPY;
+ }
+ if (childStatus.getSeverity() != IStatus.OK) {
+ VersionedIdentifier versionID = childFeature.getVersionedIdentifier();
+ String featureVer = (versionID == null) ? "" : versionID.getVersion().toString(); //$NON-NLS-1$
+ String msg1 = NLS.bind(Messages.SiteLocal_NestedFeatureUnHappy, (new String[] {childFeature.getLabel(), featureVer}));
+ multiTemp.add(createStatus(IStatus.ERROR, childStatus.getCode(), msg1, null));
+ if (childStatus.getCode() > code)
+ code = childStatus.getCode();
+ }
+ }
+ }
+ }
+ }
+
+ // set message
+ switch (code) {
+ case IFeature.STATUS_HAPPY :
+ msg = Messages.SiteLocal_FeatureHappy;
+ break;
+ case IFeature.STATUS_UNHAPPY :
+ msg = Messages.SiteLocal_FeatureUnHappy;
+ break;
+ case IFeature.STATUS_AMBIGUOUS :
+ msg = Messages.SiteLocal_FeatureAmbiguous;
+ break;
+ case IFeature.STATUS_DISABLED :
+ msg = Messages.SiteLocal_FeatureDisable;
+ break;
+ default :
+ msg = Messages.SiteLocal_FeatureStatusUnknown;
+ break;
+ }
+ MultiStatus multi = new MultiStatus(featureStatus.getPlugin(), code, msg, null);
+ multi.addAll(multiTemp);
+ return multi;
+ }
+
+ /*
+ * compute the status based on getStatus() rules
+ */
+ private IStatus status(IFeature pluginsOriginatorFeature, IPluginEntry[] featurePlugins) {
+ VersionedIdentifier featurePluginID;
+
+ String happyMSG = Messages.SiteLocal_FeatureHappy;
+ String ambiguousMSG = Messages.SiteLocal_FeatureAmbiguous;
+ IStatus featureStatus = createStatus(IStatus.OK, IFeature.STATUS_HAPPY, "", null); //$NON-NLS-1$
+ MultiStatus multi = new MultiStatus(featureStatus.getPlugin(), IFeature.STATUS_AMBIGUOUS, ambiguousMSG, null);
+ PackageAdmin pkgAdmin = UpdateCore.getPlugin().getPackageAdmin();
+
+ // is Ambigous if we find a plugin from the feature
+ // with a different version and not the one we are looking
+ for (int i = 0; i < featurePlugins.length; i++) {
+ MultiStatus tempmulti = new MultiStatus(featureStatus.getPlugin(), IFeature.STATUS_AMBIGUOUS, ambiguousMSG, null);
+ featurePluginID = featurePlugins[i].getVersionedIdentifier();
+ boolean found = false;
+
+ String singleVersionRange = '[' + featurePluginID.getVersion().toString() + ',' + featurePluginID.getVersion().toString() + ']';
+ Bundle[] bundles = pkgAdmin.getBundles(featurePluginID.getIdentifier(), singleVersionRange);
+ if (bundles != null && bundles.length == 1) {
+ found = true;
+ continue;
+ }
+
+ // Check if there is another feature with this plugin (but different version)
+ // log it
+ bundles = pkgAdmin.getBundles(featurePluginID.getIdentifier(), null);
+ for (int j = 0; bundles != null && j < bundles.length && !found; j++) {
+ String bundleVersion = (String) bundles[j].getHeaders().get(Constants.BUNDLE_VERSION);
+ IFeature feature = getFeatureForId(new VersionedIdentifier(bundles[j].getSymbolicName(), bundleVersion));
+ if ((feature != null) && (!isFeaturePatchOfThisFeature(pluginsOriginatorFeature, feature))) {
+ String msg = null;
+ String label = feature.getLabel();
+ String featureVersion = feature.getVersionedIdentifier().getVersion().toString();
+ Object[] values = new Object[] {bundles[j].getSymbolicName(), featurePluginID.getVersion(), bundleVersion, label, featureVersion};
+ msg = NLS.bind(Messages.SiteLocal_TwoVersionSamePlugin2, values);
+ UpdateCore.warn("Found another version of the same plugin on the path:" + bundles[j].getSymbolicName() + " " + bundleVersion); //$NON-NLS-1$ //$NON-NLS-2$
+ tempmulti.add(createStatus(IStatus.ERROR, IFeature.STATUS_AMBIGUOUS, msg, null));
+ } else {
+ found = true;
+ }
+
+ }
+
+ // check whether the plugin is a source bundle
+ // that has not been configured into the runtime
+ if (!found) {
+ loadSourceBundlesList();
+ for (Iterator iter = sourceBundles.iterator(); iter.hasNext();) {
+ VersionedIdentifier nextId = (VersionedIdentifier) iter.next();
+ if (featurePluginID.equals(nextId)) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ // if we haven't found the exact plugin, add the children
+ // of tempMulti (i,e the other we found)
+ // if we have no children, we have a problem as a required plugin is not there at all
+ if (!found) {
+ if (tempmulti.getChildren().length > 0) {
+ multi.addAll(tempmulti);
+ } else {
+ if (multi.getCode() != IFeature.STATUS_UNHAPPY) {
+ String unhappyMSG = Messages.SiteLocal_FeatureUnHappy;
+ MultiStatus newMulti = new MultiStatus(featureStatus.getPlugin(), IFeature.STATUS_UNHAPPY, unhappyMSG, null);
+ newMulti.addAll(multi);
+ multi = newMulti;
+ }
+ String msg = NLS.bind(Messages.SiteLocal_NoPluginVersion, (new String[] {featurePluginID.getIdentifier()}));
+ multi.add(createStatus(IStatus.ERROR, IFeature.STATUS_UNHAPPY, msg, null));
+ }
+ }
+ }
+
+ if (!multi.isOK())
+ return multi;
+
+ // we return happy as we consider the isBroken verification has been done
+ return createStatus(IStatus.OK, IFeature.STATUS_HAPPY, happyMSG, null);
+ }
+
+ public static File toFile(URL url) {
+ try {
+ if (!"file".equalsIgnoreCase(url.getProtocol())) //$NON-NLS-1$
+ return null;
+ //assume all illegal characters have been properly encoded, so use URI class to unencode
+ return new File(new URI(url.toExternalForm()));
+ } catch (Exception e) {
+ //URL contains unencoded characters
+ return new File(url.getFile());
+ }
+ }
+
+ /**
+ * Get the contents of the source bundles text file.
+ */
+ private void loadSourceBundlesList() {
+ if (sourceBundles != null)
+ return;
+
+ sourceBundles = new ArrayList(32);
+ IPlatformConfiguration config = ConfiguratorUtils.getCurrentPlatformConfiguration();
+ URL configLocation = config.getConfigurationLocation();
+ if (configLocation == null)
+ return;
+ // Drop off /org.eclipse.update/platform.xml
+ File configDir = toFile(configLocation);
+ configDir = configDir.getParentFile();
+ if (configDir == null)
+ return;
+ configDir = configDir.getParentFile();
+ if (configDir == null)
+ return;
+ File sourceBundlesFile = new File(configDir, SOURCE_BUNDLES_PATH);
+
+ try {
+ BufferedReader reader = new BufferedReader(new FileReader(sourceBundlesFile));
+ String line;
+ try {
+ while ((line = reader.readLine()) != null) {
+ if (line.startsWith("#"))
+ continue;
+ line = line.trim();// symbolicName,version,other ignored stuff
+ if (line.length() == 0)
+ continue;
+
+ StringTokenizer tok = new StringTokenizer(line, ",", true);
+ String symbolicName = tok.nextToken();
+ if (symbolicName.equals(","))
+ continue;
+ else
+ tok.nextToken(); // ,
+
+ String version = tok.nextToken();
+ if (version.equals(","))
+ continue;
+ else
+ tok.nextToken(); // ,
+
+ VersionedIdentifier sourceId = new VersionedIdentifier(symbolicName, version);
+ sourceBundles.add(sourceId);
+ }
+ } finally {
+ try {
+ reader.close();
+ } catch (IOException ex) {
+ // ignore
+ }
+ }
+ } catch (MalformedURLException e) {
+ UpdateCore.log(new Status(IStatus.ERROR, ID, "Error occurred while reading source bundle list.", e)); //$NON-NLS-1$
+ } catch (IOException e) {
+ UpdateCore.log(new Status(IStatus.ERROR, ID, "Error occurred while reading source bundle list.", e)); //$NON-NLS-1$
+ }
+ }
+
+ private boolean isFeaturePatchOfThisFeature(IFeature pluginsOriginatorFeature, IFeature feature) {
+
+ if (!feature.isPatch())
+ return false;
+
+ IImport[] featureImports = feature.getImports();
+
+ if (featureImports == null) {
+ return false;
+ }
+
+ for (int i = 0; i < featureImports.length; i++) {
+ if (featureImports[i].isPatch() && featureImports[i].getVersionedIdentifier().equals(pluginsOriginatorFeature.getVersionedIdentifier())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /*
+ * creates a Status
+ */
+ private IStatus createStatus(int statusSeverity, int statusCode, String msg, Exception e) {
+ String id = UpdateCore.getPlugin().getBundle().getSymbolicName();
+
+ StringBuffer completeString = new StringBuffer(""); //$NON-NLS-1$
+ if (msg != null)
+ completeString.append(msg);
+ if (e != null) {
+ completeString.append("\r\n["); //$NON-NLS-1$
+ completeString.append(e.toString());
+ completeString.append("]\r\n"); //$NON-NLS-1$
+ }
+ return new Status(statusSeverity, id, statusCode, completeString.toString(), e);
+ }
+
+ /*
+ * returns all the configured fetaures
+ */
+ private IFeature[] getAllConfiguredFeatures() {
+ if (allConfiguredFeatures == null) {
+
+ allConfiguredFeatures = new ArrayList();
+ IConfiguredSite[] allConfiguredSites = siteLocal.getCurrentConfiguration().getConfiguredSites();
+
+ for (int i = 0; i < allConfiguredSites.length; i++) {
+ IFeatureReference[] refs = allConfiguredSites[i].getConfiguredFeatures();
+ IFeature feature = null;
+ for (int j = 0; j < refs.length; j++) {
+ feature = null;
+ try {
+ feature = refs[j].getFeature(null);
+ } catch (CoreException e) {
+ }
+ if (feature != null) {
+ allConfiguredFeatures.add(feature);
+ }
+ }
+ }
+ }
+
+ IFeature[] features = new IFeature[allConfiguredFeatures.size()];
+ if (allConfiguredFeatures.size() > 0) {
+ allConfiguredFeatures.toArray(features);
+ }
+ return features;
+ }
+
+ /*
+ * returns the Feature that declares this versionedIdentifier or null if none found
+ */
+ private IFeature getFeatureForId(VersionedIdentifier id) {
+
+ if (id == null)
+ return null;
+
+ IFeature[] allFeatures = getAllConfiguredFeatures();
+ IFeature currentFeature = null;
+ IPluginEntry[] allPlugins = null;
+ IPluginEntry currentPlugin = null;
+ for (int i = 0; i < allFeatures.length; i++) {
+ currentFeature = allFeatures[i];
+ allPlugins = currentFeature.getPluginEntries();
+ for (int j = 0; j < allPlugins.length; j++) {
+ currentPlugin = allPlugins[j];
+ if (id.equals(currentPlugin.getVersionedIdentifier()))
+ return currentFeature;
+ }
+ }
+ return null;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteTypeFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteTypeFactory.java
new file mode 100644
index 0000000..5526f76
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteTypeFactory.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+
+/**
+ *
+ */
+public final class SiteTypeFactory {
+
+
+ /**
+ * extension point ID
+ */
+ public static final String SIMPLE_EXTENSION_ID = "siteTypes"; //$NON-NLS-1$
+
+
+ private static SiteTypeFactory inst;
+
+ private Map factories;
+
+ /**
+ * hide ctr
+ */
+ private SiteTypeFactory() {
+ }
+
+ public static SiteTypeFactory getInstance() {
+ if (inst == null)
+ inst = new SiteTypeFactory();
+ return inst;
+ }
+
+
+ /**
+ * return the factory for the type
+ */
+ public ISiteFactory getFactory(String type) throws CoreException {
+ //
+ Object instance = getFactories().get(type);
+ if (instance==null) {
+ instance = createFactoryFor(type);
+ getFactories().put(type,instance);
+ }
+ return (ISiteFactory) instance;
+ }
+
+ /**
+ *
+ */
+ private ISiteFactory createFactoryFor(String type) throws CoreException {
+ ISiteFactory result = null;
+
+ String pluginID = UpdateCore.getPlugin().getBundle().getSymbolicName();
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IConfigurationElement[] elements = registry.getConfigurationElementsFor(pluginID,SIMPLE_EXTENSION_ID,type);
+ if (elements==null || elements.length==0){
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteTypeFactory_UnableToFindSiteFactory, (new String[] { type })),null);
+ } else {
+ IConfigurationElement element = elements[0];
+ result = (ISiteFactory)element.createExecutableExtension("class"); //$NON-NLS-1$
+ }
+ return result;
+ }
+
+ /**
+ * Gets the actories.
+ * @return Returns a Map
+ */
+ private Map getFactories() {
+ if (factories==null) factories = new HashMap();
+ return factories;
+ }
+
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteURLContentProvider.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteURLContentProvider.java
new file mode 100644
index 0000000..a6070c9
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteURLContentProvider.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+import java.net.URL;
+
+import org.eclipse.update.core.SiteContentProvider;
+
+/**
+ *
+ */
+public class SiteURLContentProvider extends SiteContentProvider {
+
+ public static final String SITE_TYPE = "org.eclipse.update.core.http"; //$NON-NLS-1$
+
+ /**
+ * Constructor for HTTPSite
+ */
+ public SiteURLContentProvider(URL url) {
+ super(url);
+ }
+}
+
+
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteURLFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteURLFactory.java
new file mode 100644
index 0000000..0540a85
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteURLFactory.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Date;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.BaseSiteFactory;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.ISiteFactoryExtension;
+import org.eclipse.update.core.Site;
+import org.eclipse.update.core.SiteFeatureReferenceModel;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.core.model.InvalidSiteTypeException;
+import org.eclipse.update.core.model.SiteModelFactory;
+import org.eclipse.update.internal.core.connection.ConnectionFactory;
+import org.eclipse.update.internal.core.connection.IResponse;
+import org.eclipse.update.internal.model.SiteWithTimestamp;
+
+/**
+ * An update site factory.
+ *
+ */
+public class SiteURLFactory extends BaseSiteFactory implements ISiteFactoryExtension {
+
+ /*
+ * For backward compatibility.
+ */
+ public ISite createSite(URL url) throws CoreException, InvalidSiteTypeException {
+ return createSite(url, null);
+ }
+ /*
+ * @see ISiteFactory#createSite(URL, boolean)
+ *
+ * the URL can be of the following form
+ * 1 protocol://...../
+ * 2 protocol://.....
+ * 3 protocol://..../site.xml
+ *
+ * 1 If the file of the file of teh url ends with '/', attempt to open the stream.
+ * if it fails, add site.xml and attempt to open the stream
+ *
+ * 2 attempt to open the stream
+ * fail
+ * add '/site.xml' and attempt to open the stream
+ * sucess
+ * attempt to parse, if it fails, add '/site.xml' and attempt to open teh stream
+ *
+ * 3 open the stream
+ */
+ public ISite createSite(URL url, IProgressMonitor monitor) throws CoreException, InvalidSiteTypeException {
+ Site site = null;
+ InputStream siteStream = null;
+
+ try {
+ SiteURLContentProvider contentProvider = new SiteURLContentProvider(url);
+
+ URL resolvedURL = URLEncoder.encode(url);
+ IResponse response = ConnectionFactory.get(resolvedURL);
+ UpdateManagerUtils.checkConnectionResult(response, resolvedURL);
+ siteStream = response.getInputStream(monitor);
+ // the stream can be null if the user cancels the connection
+ if (siteStream==null) return null;
+
+ SiteModelFactory factory = this;
+ site = (Site) factory.parseSite(siteStream);
+ //System.out.println(site.getClass().getCanonicalName());
+ site.setSiteContentProvider(contentProvider);
+ contentProvider.setSite(site);
+ site.resolve(url, url);
+ site.markReadOnly();
+ /*SiteWithTimestamp siteWithTimestamp = new SiteWithTimestamp(site);
+ siteWithTimestamp.setTimestamp( new Date(response.getLastModified()));
+ site = siteWithTimestamp;*/
+ ((SiteWithTimestamp)site).setTimestamp( new Date(response.getLastModified()));
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteURLFactory_UnableToCreateURL, (new String[] { url == null ? "" : url.toExternalForm() })), e); //$NON-NLS-1$
+ } catch (IOException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.SiteURLFactory_UnableToAccessSiteStream, (new String[] { url == null ? "" : url.toExternalForm() })), ISite.SITE_ACCESS_EXCEPTION, e); //$NON-NLS-1$
+ } finally {
+ if (siteStream != null) {
+ try {
+ siteStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ return site;
+ }
+
+ /*
+ * @see SiteModelFactory#canParseSiteType(String)
+ */
+ public boolean canParseSiteType(String type) {
+ return (super.canParseSiteType(type) || SiteURLContentProvider.SITE_TYPE.equalsIgnoreCase(type));
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.update.core.BaseSiteFactory#createFeatureReferenceModel()
+ */
+ public SiteFeatureReferenceModel createFeatureReferenceModel() {
+ return new UpdateSiteFeatureReference();
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/TargetFeature.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/TargetFeature.java
new file mode 100644
index 0000000..6c789f1
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/TargetFeature.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.Feature;
+import org.eclipse.update.core.IFeatureContentConsumer;
+import org.eclipse.update.core.Utilities;
+
+/**
+ *
+ */
+public class TargetFeature extends Feature {
+
+
+ /**
+ * The content consumer of the DefaultFeature
+ */
+ private IFeatureContentConsumer contentConsumer;
+
+
+ /**
+ * Constructor for TargetFeature.
+ */
+ public TargetFeature() {
+ super();
+ }
+
+ /**
+ * Sets the content Consumer
+ */
+ public void setContentConsumer(IFeatureContentConsumer contentConsumer) {
+ this.contentConsumer = contentConsumer;
+ contentConsumer.setFeature(this);
+ }
+
+ /*
+ * @see IFeature#getFeatureContentConsumer()
+ */
+ public IFeatureContentConsumer getFeatureContentConsumer() throws CoreException {
+ if (this.contentConsumer == null) {
+ throw Utilities.newCoreException( NLS.bind(Messages.Feature_NoFeatureContentConsumer, (new String[] { getURL().toExternalForm() })), null);
+ }
+ return contentConsumer;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/URLEncoder.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/URLEncoder.java
new file mode 100644
index 0000000..3200a9f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/URLEncoder.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ * James D Miles (IBM Corp.) - bug 191368, Policy URL doesn't support UTF-8 characters
+ *******************************************************************************/
+package org.eclipse.update.internal.core;
+
+
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.runtime.Assert;
+/**
+ * Encodes a <code>URL</code> into an <code>ASCII</code> readable
+ * <code>URL</code> that is safe for transport. Encoded
+ * <code>URL</code>s can be decoded using the <code>URLDecoder</code>.
+ *
+ * @see URLDecoder
+ */
+public final class URLEncoder {
+ /**
+ * Prevents instances from being created.
+ */
+ private URLEncoder() {
+ }
+ /**
+ * Encodes the given file and reference parts of a <code>URL</code> into
+ * an <code>ASCII</code> readable <code>String</code> that is safe for
+ * transport. Returns the result.
+ *
+ * @return the result of encoding the given file and reference parts of
+ * a <code>URL</code> into an <code>ASCII</code> readable
+ * <code>String</code> that is safe for transport
+ */
+ public static String encode(String file, String query, String ref) {
+ StringBuffer buf = new StringBuffer();
+ StringTokenizer tokenizer = new StringTokenizer(file, "/", true); //$NON-NLS-1$
+
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ if (token.equals("/")) { //$NON-NLS-1$
+ buf.append(token);
+ } else {
+ buf.append(encodeSegment(token));
+ }
+ }
+
+ if (query != null){
+ buf.append('?');
+ buf.append(query);
+ }
+
+ if (ref != null) {
+ buf.append('#');
+ buf.append(encodeSegment(ref));
+ }
+
+ return buf.toString();
+ }
+ /**
+ * Encodes the given <code>URL</code> into an <code>ASCII</code>
+ * readable <code>URL</code> that is safe for transport. Returns the
+ * result.
+ *
+ * @return the result of encoding the given <code>URL</code> into an
+ * <code>ASCII</code> readable <code>URL</code> that is safe for
+ * transport
+ */
+ public static URL encode(URL url) throws MalformedURLException {
+ // encode the path not the file as the URL may contain a query
+ String file = url.getPath();
+ String query = url.getQuery();
+ String ref = url.getRef();
+ String auth = url.getAuthority();
+ String host = url.getHost();
+ int port = url.getPort();
+ String userinfo = url.getUserInfo();
+
+ // do not encode if there is an authority, such as in
+ // ftp://user:password@host:port/path
+ // because the URL constructor does not allow it
+ URL result = url;
+ if (auth == null || auth.equals("") || userinfo == null) // $NON-NLS-1$ $NON-NLS-2$ //$NON-NLS-1$
+ result = new URL(url.getProtocol(), host, port, encode(file, query, ref));
+ return result;
+ }
+ private static String encodeSegment(String segment) {
+
+ // if we find a '%' in the string, consider the URL to be already encoded
+ if (segment.indexOf('%')!=-1) return segment;
+
+ StringBuffer result = new StringBuffer(segment.length());
+
+ for (int i = 0; i < segment.length(); ++i) {
+ char c = segment.charAt(i);
+ if (mustEncode(c)) {
+ byte[] bytes = null;
+ try {
+ bytes = new Character(c).toString().getBytes("UTF8"); //$NON-NLS-1$
+ } catch (UnsupportedEncodingException e) {
+ Assert.isTrue(false, e.getMessage());
+ }
+ for (int j = 0; j < bytes.length; ++j) {
+ result.append('%');
+ result.append(Integer.toHexString((bytes[j] >> 4) & 0x0F));
+ result.append(Integer.toHexString(bytes[j] & 0x0F));
+ }
+ } else {
+ result.append(c);
+ }
+ }
+
+ return result.toString();
+ }
+
+ private static boolean mustEncode(char c) {
+ if (c >= 'a' && c <= 'z') {
+ return false;
+ }
+
+ if (c >= 'A' && c <= 'Z') {
+ return false;
+ }
+
+ if (c >= '0' && c <= '9') {
+ return false;
+ }
+
+ if (c >= '\'' && c <= '.') {
+ return false;
+ }
+
+ if (c == '!' || c == '$' || c == '_' || c == '[' || c == ']') {
+ return false;
+ }
+
+ // needed otherwise file:///c:/file/ becomes file:///C%3a/file/
+ if (c ==':'){
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/URLKey.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/URLKey.java
new file mode 100644
index 0000000..75c76ad
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/URLKey.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+
+import java.net.*;
+
+
+
+/**
+ *
+ *
+ */
+public class URLKey {
+
+ private URL url;
+
+ /**
+ * Constructor for URLKey.
+ */
+ public URLKey(URL url) {
+ super();
+ this.url = url;
+ }
+
+ /**
+ * @see java.lang.Object#equals(Object)
+ */
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof URLKey) {
+ return equals(((URLKey) obj).getURL());
+ }
+
+ if (!(obj instanceof URL)) {
+ return false;
+ }
+
+ URL url2 = (URL)obj;
+ if (url == url2) {
+ return true;
+ }
+
+ return UpdateManagerUtils.sameURL(url,url2);
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return url.hashCode();
+ }
+
+ /**
+ * Returns the url.
+ * @return URL
+ */
+ public URL getURL() {
+ return url;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateCore.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateCore.java
new file mode 100644
index 0000000..0707949
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateCore.java
@@ -0,0 +1,320 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import org.eclipse.core.net.proxy.IProxyService;
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.signedcontent.SignedContentFactory;
+import org.eclipse.update.configuration.IInstallConfiguration;
+import org.eclipse.update.configurator.ConfiguratorUtils;
+import org.eclipse.update.configurator.IPlatformConfiguration;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.connection.ConnectionThreadManagerFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * The main plugin class to be used in the desktop.
+ */
+public class UpdateCore extends Plugin {
+
+ // debug options
+ public static boolean DEBUG;
+ public static boolean DEBUG_SHOW_INSTALL;
+ public static boolean DEBUG_SHOW_PARSING;
+ public static boolean DEBUG_SHOW_WARNINGS;
+ public static boolean DEBUG_SHOW_CONFIGURATION;
+ public static boolean DEBUG_SHOW_TYPE;
+ public static boolean DEBUG_SHOW_WEB;
+ public static boolean DEBUG_SHOW_IHANDLER;
+ public static boolean DEBUG_SHOW_RECONCILER;
+
+ private static final String PREFIX = "org.eclipse.update.core"; //$NON-NLS-1$
+ public static final String P_HISTORY_SIZE = PREFIX + ".historySize"; //$NON-NLS-1$
+ public static final String P_CHECK_SIGNATURE = PREFIX + ".checkSignature"; //$NON-NLS-1$
+ public static final String P_AUTOMATICALLY_CHOOSE_MIRROR = PREFIX + ".automaticallyChooseMirror"; //$NON-NLS-1$
+ public static final String P_UPDATE_VERSIONS = PREFIX + ".updateVersions"; //$NON-NLS-1$
+ public static final String EQUIVALENT_VALUE = "equivalent"; //$NON-NLS-1$
+ public static final String COMPATIBLE_VALUE = "compatible"; //$NON-NLS-1$
+
+ public static int DEFAULT_HISTORY = 100;//Integer.MAX_VALUE;
+
+ //The shared instance.
+ private static UpdateCore plugin;
+
+ //log
+ private static UpdateManagerLogWriter log;
+ private static final String LOG_FILE="install.log"; //$NON-NLS-1$
+
+ // bundle data
+ private BundleContext context;
+ private ServiceTracker pkgAdminTracker;
+ private ServiceTracker verifierFactoryTracker;
+ private ServiceTracker proxyTracker;
+
+ // Session
+ private UpdateSession updateSession = null;
+ /**
+ * HTTP response code indicating success.
+ */
+ public static final int HTTP_OK = 200;
+
+ /**
+ * The constructor.
+ */
+ public UpdateCore() {
+ plugin = this;
+ }
+
+
+ /**
+ * Returns the shared instance.
+ */
+ public static UpdateCore getPlugin() {
+ return plugin;
+ }
+
+
+ private boolean getBooleanDebugOption(String flag, boolean dflt) {
+ String result = Platform.getDebugOption(flag);
+ if (result == null)
+ return dflt;
+ else
+ return result.trim().equalsIgnoreCase("true"); //$NON-NLS-1$
+ }
+
+ /**
+ * dumps a String in the trace
+ */
+ public static void debug(String s) {
+ StringBuffer msg = new StringBuffer();
+ msg.append(getPlugin().toString());
+ msg.append("^"); //$NON-NLS-1$
+ msg.append(Integer.toHexString(Thread.currentThread().hashCode()));
+ msg.append(" "); //$NON-NLS-1$
+ msg.append(s);
+ System.out.println(msg.toString());
+ }
+
+ /**
+ * Dumps a String in the log if WARNING is set to true
+ */
+ public static void warn(String s) {
+ if (DEBUG && DEBUG_SHOW_WARNINGS) {
+ if (s!=null){
+ s="WARNING: "+s; //$NON-NLS-1$
+ }
+ log(s, null);
+ }
+ }
+
+ /**
+ * Dumps an exception in the log if WARNING is set to true
+ *
+ * @param s log string
+ * @param e exception to be logged
+ * @since 2.0
+ */
+ public static void warn(String s, Throwable e) {
+ if (DEBUG && DEBUG_SHOW_WARNINGS){
+ if (s!=null){
+ s="UPDATE MANAGER INFO: "+s; //$NON-NLS-1$
+ }
+ log(s,e);
+ }
+ }
+
+ /**
+ * Logs a status
+ */
+ public static void log(IStatus status){
+ UpdateCore.getPlugin().getLog().log(status);
+ }
+
+ /**
+ * Logs an error
+ */
+ public static void log(Throwable e){
+ log("",e); //$NON-NLS-1$
+ }
+
+ /**
+ * Logs a string and an error
+ */
+ public static void log(String msg, Throwable e){
+ IStatus status = null;
+ if (e instanceof CoreException)
+ status = ((CoreException)e).getStatus();
+ else
+ status = Utilities.newCoreException(msg,e).getStatus();
+ if (status!=null)
+ log(status);
+ }
+ /*
+ * Method log.
+ * @param newConfiguration
+ */
+ public static void log(IInstallConfiguration newConfiguration) {
+ if (log!=null)
+ log.log(newConfiguration);
+ }
+
+ /*
+ * Get update log location relative to platform configuration
+ */
+ private static File getInstallLogFile() throws IOException {
+
+ IPlatformConfiguration config = ConfiguratorUtils.getCurrentPlatformConfiguration();
+ URL configurationLocation = config.getConfigurationLocation();
+ if (configurationLocation==null){
+ warn("Unable to retrieve location for update manager log file"); //$NON-NLS-1$
+ return null;
+ }
+// URL configLocation = Platform.resolve(configurationLocation);
+ File updateStateLocation = null;
+
+ if ("file".equalsIgnoreCase(configurationLocation.getProtocol())) { //$NON-NLS-1$
+ File path = new File(configurationLocation.getFile());
+ updateStateLocation = new File(path.getParentFile(), LOG_FILE);
+ }
+ return updateStateLocation;
+ }
+
+ /**
+ * Sends the GET request to the server and returns the server's
+ * response.
+ *
+ * @param url the URL to open on the server
+ * @return the server's response
+ * @throws IOException if an I/O error occurs. Reasons include:
+ * <ul>
+ * <li>The client is closed.
+ * <li>The client could not connect to the server
+ * <li>An I/O error occurs while communicating with the server
+ * <ul>
+ */
+
+
+ /*
+ * Returns true if the feature is a patch
+ */
+ public static boolean isPatch(IFeature candidate) {
+ IImport[] imports = candidate.getImports();
+
+ for (int i = 0; i < imports.length; i++) {
+ IImport iimport = imports[i];
+ if (iimport.isPatch())
+ return true;
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ this.context = context;
+
+ DEBUG = getBooleanDebugOption("org.eclipse.update.core/debug", false); //$NON-NLS-1$
+
+ if (DEBUG) {
+ DEBUG_SHOW_WARNINGS = getBooleanDebugOption("org.eclipse.update.core/debug/warning", false); //$NON-NLS-1$
+ DEBUG_SHOW_PARSING = getBooleanDebugOption("org.eclipse.update.core/debug/parsing", false); //$NON-NLS-1$
+ DEBUG_SHOW_INSTALL = getBooleanDebugOption("org.eclipse.update.core/debug/install", false); //$NON-NLS-1$
+ DEBUG_SHOW_CONFIGURATION = getBooleanDebugOption("org.eclipse.update.core/debug/configuration", false); //$NON-NLS-1$
+ DEBUG_SHOW_TYPE = getBooleanDebugOption("org.eclipse.update.core/debug/type", false); //$NON-NLS-1$
+ DEBUG_SHOW_WEB = getBooleanDebugOption("org.eclipse.update.core/debug/web", false); //$NON-NLS-1$
+ DEBUG_SHOW_IHANDLER = getBooleanDebugOption("org.eclipse.update.core/debug/installhandler", false); //$NON-NLS-1$
+ DEBUG_SHOW_RECONCILER = getBooleanDebugOption("org.eclipse.update.core/debug/reconciler", false); //$NON-NLS-1$
+ }
+
+ //
+ try {
+ File logFile = getInstallLogFile();
+ if (logFile!=null)
+ log = new UpdateManagerLogWriter(logFile);
+ } catch (IOException e){
+ warn("",e); //$NON-NLS-1$
+ }
+ }
+ /* (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+
+ JarContentReference.shutdown(); // make sure we are not leaving jars open
+ Utilities.shutdown(); // cleanup temp area
+ if (log!=null)
+ log.shutdown();
+
+ ConnectionThreadManagerFactory.getConnectionManager().shutdown();
+
+
+ this.context = null;
+ if (pkgAdminTracker != null) {
+ pkgAdminTracker.close();
+ pkgAdminTracker = null;
+ }
+ if (verifierFactoryTracker != null) {
+ verifierFactoryTracker.close();
+ verifierFactoryTracker = null;
+ }
+ if (proxyTracker != null) {
+ proxyTracker.close();
+ proxyTracker = null;
+ }
+ }
+
+ public BundleContext getBundleContext() {
+ return context;
+ }
+
+ PackageAdmin getPackageAdmin() {
+ if (pkgAdminTracker == null) {
+ pkgAdminTracker = new ServiceTracker(context, PackageAdmin.class.getName(), null);
+ pkgAdminTracker.open();
+ }
+ return (PackageAdmin)pkgAdminTracker.getService();
+ }
+
+ public IProxyService getProxyService() {
+ if (proxyTracker == null) {
+ proxyTracker=new ServiceTracker(getBundle().getBundleContext(),
+ IProxyService.class.getName(), null);
+ proxyTracker.open();
+ }
+ return (IProxyService)proxyTracker.getService();
+ }
+
+
+ public SignedContentFactory getSignedContentFactory() {
+ if (verifierFactoryTracker == null) {
+ verifierFactoryTracker = new ServiceTracker(context, SignedContentFactory.class.getName(), null);
+ verifierFactoryTracker.open();
+ }
+ return (SignedContentFactory)verifierFactoryTracker.getService();
+ }
+
+ public UpdateSession getUpdateSession() {
+ synchronized(UpdateSession.class) {
+ if (updateSession == null) {
+ updateSession = new UpdateSession();
+ }
+ }
+ return updateSession;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateManagerLogWriter.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateManagerLogWriter.java
new file mode 100644
index 0000000..1daf0ca
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateManagerLogWriter.java
@@ -0,0 +1,301 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.update.configuration.IActivity;
+import org.eclipse.update.configuration.IInstallConfiguration;
+import org.eclipse.update.configurator.ConfiguratorUtils;
+import org.eclipse.update.configurator.IPlatformConfiguration;
+
+
+/**
+ * A log writer that writes update manager log entries.
+ */
+public class UpdateManagerLogWriter {
+ private File logFile = null;
+ private Writer log = null;
+
+ private static final String CONFIGURATION = "!CONFIGURATION"; //$NON-NLS-1$
+ private static final String ACTIVITY = "!ACTIVITY"; //$NON-NLS-1$
+
+ private static final String SUCCESS = "success"; //$NON-NLS-1$
+ private static final String FAILURE = "failure"; //$NON-NLS-1$
+
+ private static final String FEATURE_INSTALL = "feature-install"; //$NON-NLS-1$
+ private static final String FEATURE_REMOVE = "feature-remove"; //$NON-NLS-1$
+ private static final String SITE_INSTALL = "site-install"; //$NON-NLS-1$
+ private static final String SITE_REMOVE = "site-remove"; //$NON-NLS-1$
+ private static final String UNCONFIGURE = "feature-disable"; //$NON-NLS-1$
+ private static final String CONFIGURE = "feature-enable"; //$NON-NLS-1$
+ private static final String REVERT = "revert"; //$NON-NLS-1$
+ private static final String RECONCILIATION = "reconciliation"; //$NON-NLS-1$
+ private static final String PRESERVED = "preserve-configuration"; //$NON-NLS-1$
+ private static final String UNKNOWN = "unknown"; //$NON-NLS-1$
+
+ private static final String LINE_SEPARATOR;
+
+ static {
+ String s = System.getProperty("line.separator"); //$NON-NLS-1$
+ LINE_SEPARATOR = s == null ? "\n" : s; //$NON-NLS-1$
+ }
+
+ /*
+ *
+ */
+ public UpdateManagerLogWriter(File file) {
+ this.logFile = file;
+ UpdateCore.warn("UPDATE MANAGER LOG Location: "+file.getAbsolutePath()); //$NON-NLS-1$
+
+ // If the file does not exist, prime it with the sites in the exisiting config
+ if (!file.exists())
+ initLog();
+ }
+
+ /*
+ * Initializes the log with the original configuration
+ */
+ private void initLog() {
+ try {
+ IPlatformConfiguration runtimeConfig = ConfiguratorUtils.getCurrentPlatformConfiguration();
+ IPlatformConfiguration.ISiteEntry[] sites = runtimeConfig.getConfiguredSites();
+ ConfigurationActivity[] activities = new ConfigurationActivity[sites.length];
+ for (int i=0; i<sites.length; i++) {
+ activities[i] = new ConfigurationActivity(IActivity.ACTION_SITE_INSTALL);
+ activities[i].setLabel(FileLocator.toFileURL(sites[i].getURL()).toExternalForm());
+ activities[i].setDate(new Date());
+ activities[i].setStatus(IActivity.STATUS_OK);
+ }
+ Date date = new Date(runtimeConfig.getChangeStamp());
+ safeWriteConfiguration(date, activities);
+ } catch (Exception e) {
+ // silently ignore errors
+ }
+ }
+
+ /*
+ *
+ */
+ private void closeLogFile() throws IOException {
+ try {
+ if (log != null) {
+ log.flush();
+ log.close();
+ }
+ } finally {
+ log = null;
+ }
+ }
+
+ /*
+ *
+ */
+ public void log(IInstallConfiguration installConfig) {
+ safeWriteConfiguration(installConfig.getCreationDate(), installConfig.getActivities());
+ }
+
+
+ /*
+ *
+ */
+ private void openLogFile() {
+ try {
+ log = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(logFile.getAbsolutePath(), true), "UTF-8")); //$NON-NLS-1$
+ } catch (IOException e) {
+ // there was a problem opening the log file so log to the console
+ log = logForStream(System.err);
+ }
+ }
+
+ /*
+ *
+ */
+ private String getFormattedDate(Date date) {
+ try {
+ DateFormat formatter = new SimpleDateFormat("MMM dd, yyyy kk:mm:ss.SS"); //$NON-NLS-1$
+ return formatter.format(date);
+ } catch (Exception e) {
+ // If there were problems writing out the date, ignore and
+ // continue since that shouldn't stop us from losing the rest
+ // of the information
+ }
+ return Long.toString(System.currentTimeMillis());
+ }
+
+ /*
+ *
+ */
+ private Writer logForStream(OutputStream output) {
+ try {
+ return new BufferedWriter(new OutputStreamWriter(output, "UTF-8")); //$NON-NLS-1$
+ } catch (UnsupportedEncodingException e) {
+ return new BufferedWriter(new OutputStreamWriter(output));
+ }
+ }
+
+
+ /*
+ * Shuts down the update manager log.
+ */
+ public synchronized void shutdown() {
+ try {
+ if (logFile != null) {
+ closeLogFile();
+ logFile = null;
+ } else {
+ if (log != null) {
+ Writer old = log;
+ log = null;
+ old.flush();
+ old.close();
+ }
+ }
+ } catch (IOException e) {
+ //we've shutdown the log, so not much else we can do!
+ e.printStackTrace();
+ }
+ }
+
+ /*
+ *
+ */
+ private synchronized void safeWriteConfiguration(Date date, IActivity[] activities) {
+ // thread safety: (Concurrency003)
+ if (logFile != null)
+ openLogFile();
+ if (log == null)
+ log = logForStream(System.err);
+ try {
+ try {
+ write(date, activities);
+ } finally {
+ if (logFile != null)
+ closeLogFile();
+ else
+ log.flush();
+ }
+ } catch (Exception e) {
+ System.err.println("An exception occurred while writing to the update manager log:"); //$NON-NLS-1$
+ e.printStackTrace(System.err);
+ System.err.println("Logging to the console instead."); //$NON-NLS-1$
+ //we failed to write, so dump log entry to console instead
+ try {
+ log = logForStream(System.err);
+ write(date, activities);
+ log.flush();
+ } catch (Exception e2) {
+ System.err.println("An exception occurred while logging to the console:"); //$NON-NLS-1$
+ e2.printStackTrace(System.err);
+ }
+ } finally {
+ log = null;
+ }
+ }
+
+
+ /*
+ * !CONFIGURATION <label>
+ */
+ private void write(Date date, IActivity[] activities) throws IOException {
+ writeln();
+ write(CONFIGURATION);
+ writeSpace();
+ write(String.valueOf(date.getTime()));
+ writeSpace();
+ write(date.toString());
+ writeln();
+ for (int i = 0; i < activities.length; i++) {
+ write(activities[i]);
+ }
+ }
+
+ /*
+ * !ACTIVITY <date> <target> <action> <status>
+ */
+ private void write(IActivity activity) throws IOException {
+ write(ACTIVITY);
+ writeSpace();
+ write(String.valueOf(activity.getDate().getTime()));
+ writeSpace();
+ write(getFormattedDate(activity.getDate()));
+ writeSpace();
+ write(activity.getLabel());
+ writeSpace();
+ write(getAction(activity.getAction()));
+ writeSpace();
+ write((activity.getStatus()==IActivity.STATUS_OK)?SUCCESS:FAILURE);
+ writeln();
+ }
+
+ /*
+ *
+ */
+ private String getAction(int i) {
+ switch (i) {
+ case IActivity.ACTION_FEATURE_INSTALL :
+ return FEATURE_INSTALL;
+ case IActivity.ACTION_FEATURE_REMOVE :
+ return FEATURE_REMOVE;
+ case IActivity.ACTION_SITE_INSTALL :
+ return SITE_INSTALL;
+ case IActivity.ACTION_SITE_REMOVE :
+ return SITE_REMOVE;
+ case IActivity.ACTION_UNCONFIGURE :
+ return UNCONFIGURE;
+ case IActivity.ACTION_CONFIGURE :
+ return CONFIGURE;
+ case IActivity.ACTION_REVERT :
+ return REVERT;
+ case IActivity.ACTION_RECONCILIATION :
+ return RECONCILIATION;
+ case IActivity.ACTION_ADD_PRESERVED :
+ return PRESERVED;
+
+ default :
+ return UNKNOWN+" ["+i+"]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+
+ /*
+ *
+ */
+ private void writeln() throws IOException {
+ write(LINE_SEPARATOR);
+ }
+
+ /*
+ *
+ */
+ private void write(String message) throws IOException {
+ if (message != null)
+ log.write(message);
+ }
+
+ /*
+ *
+ */
+ private void writeSpace() throws IOException {
+ write(" "); //$NON-NLS-1$
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateManagerUtils.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateManagerUtils.java
new file mode 100644
index 0000000..d1e713a
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateManagerUtils.java
@@ -0,0 +1,964 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2009 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
+ * Chris Aniszczyk (IBM Corp.) - Fixed NPE
+ *******************************************************************************/
+package org.eclipse.update.internal.core;
+
+import org.eclipse.update.core.IUpdateConstants;
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+import org.eclipse.update.core.model.InstallAbortedException;
+import org.eclipse.update.internal.core.connection.ConnectionFactory;
+import org.eclipse.update.internal.core.connection.IResponse;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+/**
+ *
+ */
+public class UpdateManagerUtils {
+
+ private static boolean OS_UNIX = org.eclipse.osgi.service.environment.Constants.OS_HPUX
+ .equals(Platform.getOS())
+ || org.eclipse.osgi.service.environment.Constants.OS_AIX
+ .equals(Platform.getOS())
+ || org.eclipse.osgi.service.environment.Constants.OS_LINUX
+ .equals(Platform.getOS())
+ || org.eclipse.osgi.service.environment.Constants.OS_SOLARIS
+ .equals(Platform.getOS())
+ || org.eclipse.osgi.service.environment.Constants.OS_MACOSX
+ .equals(Platform.getOS());
+ private static FragmentEntry[] noFragments = new FragmentEntry[0];
+ private static Map table;
+
+ static {
+ table = new HashMap();
+ table.put("compatible", new Integer(IUpdateConstants.RULE_COMPATIBLE)); //$NON-NLS-1$
+ table.put("perfect", new Integer(IUpdateConstants.RULE_PERFECT)); //$NON-NLS-1$
+ table.put("equivalent", new Integer(IUpdateConstants.RULE_EQUIVALENT)); //$NON-NLS-1$
+ table.put("greaterOrEqual", new Integer(IUpdateConstants.RULE_GREATER_OR_EQUAL)); //$NON-NLS-1$
+ }
+
+ // manage URL to File
+ private static Map urlFileMap;
+
+ private static Map localFileFragmentMap;
+ private static Stack bufferPool;
+ private static final int BUFFER_SIZE = 4096; // 4kbytes
+ private static final int INCREMENT_SIZE = 10240; // 10kbytes
+ /**
+ * return the urlString if it is a absolute URL
+ * otherwise, return the default URL if the urlString is null
+ * The defaultURL may point ot a file, create a file URL then
+ * if the urlString or the default URL are relatives, prepend the rootURL to it
+ */
+ public static URL getURL(URL rootURL, String urlString, String defaultURL) throws MalformedURLException {
+ URL url = null;
+
+ // if no URL , provide Default
+ if (urlString == null || urlString.trim().equals("")) { //$NON-NLS-1$
+
+ // no URL, no default, return right now...
+ if (defaultURL == null || defaultURL.trim().equals("")) //$NON-NLS-1$
+ return null;
+ else
+ urlString = defaultURL;
+ }
+
+ // URL can be relative or absolute
+ if (urlString.startsWith("/") && urlString.length() > 1) //$NON-NLS-1$
+ urlString = urlString.substring(1);
+ try {
+ url = new URL(urlString);
+ } catch (MalformedURLException e) {
+ // the url is not an absolute URL
+ // try relative
+ url = new URL(rootURL, urlString);
+ }
+
+ return url;
+ }
+
+ /**
+ * return a relative String to rootURL
+ * if url contains rootURL so
+ * new URL(rootURL, resultString) == url
+ *
+ */
+ public static String getURLAsString(URL rootURL, URL url) {
+ String result = null;
+
+ if (rootURL == null) {
+ return (url == null) ? null : url.toString();
+ }
+
+ // if no URL , return null
+ if (url != null) {
+
+ result = url.toExternalForm();
+
+ if (rootURL.getHost() != null && !rootURL.getHost().equals(url.getHost()))
+ return result;
+
+ if (rootURL.getProtocol() != null && !rootURL.getProtocol().equals(url.getProtocol()))
+ return result;
+
+ if (rootURL.getPort() != url.getPort())
+ return result;
+
+ String rootURLFileString = rootURL.getFile();
+ rootURLFileString = rootURLFileString.replace(File.separatorChar, '/');
+ if (!rootURLFileString.endsWith("/")) { //$NON-NLS-1$
+ int index = rootURLFileString.lastIndexOf('/');
+ if (index != -1) {
+ rootURLFileString = rootURLFileString.substring(0, index);
+ }
+ }
+ String urlFileString = url.getFile();
+
+ if (urlFileString.startsWith(rootURLFileString)) {
+ result = urlFileString.substring(rootURLFileString.length());
+ result = result.replace(File.separatorChar, '/');
+ } else {
+ // we need to check the following
+ // file:/C:/ and file:C:/
+ if ("file".equalsIgnoreCase(url.getProtocol())) { //$NON-NLS-1$
+ File rootFile = new File(rootURLFileString);
+ File urlFile = new File(urlFileString);
+
+ File relativePath = urlFile;
+ while (relativePath != null && !rootFile.equals(relativePath.getParentFile())) {
+ relativePath = relativePath.getParentFile();
+ }
+
+ if (relativePath == null) {
+ UpdateCore.warn("Cannot calculate relative path"); //$NON-NLS-1$
+ return url.toString();
+ } else {
+ String relativeRootString = relativePath.getParentFile().getAbsolutePath();
+ String fullString = urlFile.getAbsolutePath();
+ if (!fullString.startsWith(relativeRootString)) {
+ UpdateCore.warn("Full path:" + fullString + " does not start with " + relativeRootString); //$NON-NLS-1$ //$NON-NLS-2$
+ return url.toString();
+ } else {
+ String returnString = fullString.substring(relativeRootString.length() + 1);
+ if (urlFile.isDirectory())
+ returnString += File.separator;
+ // we lost the last slash when tranforming in File
+ returnString = returnString.replace(File.separatorChar, '/');
+ return returnString;
+ }
+
+ }
+
+ } else {
+ result = url.toString();
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * returns a translated String
+ */
+ public static String getResourceString(String infoURL, ResourceBundle bundle) {
+ String result = null;
+ if (infoURL != null) {
+ result = Platform.getResourceString(UpdateCore.getPlugin().getBundle(), infoURL, bundle);
+ }
+ return result;
+ }
+
+ /**
+ *
+ */
+ public static URL copyToLocal(InputStream sourceContentReferenceStream, String localName, InstallMonitor monitor) throws MalformedURLException, IOException, InstallAbortedException {
+ URL result = null;
+ // create the Dir if they do not exist
+ // get the path from the File to resolve File.separator..
+ // do not use the String as it may contain URL like separator
+ File localFile = new File(localName);
+ int index = localFile.getPath().lastIndexOf(File.separator);
+ if (index != -1) {
+ File dir = new File(localFile.getPath().substring(0, index));
+ if (!dir.exists())
+ dir.mkdirs();
+ }
+
+ // transfer the content of the File
+ if (!localFile.isDirectory()) {
+ OutputStream localContentReferenceStream = new FileOutputStream(localFile);
+ try {
+ Utilities.copy(sourceContentReferenceStream, localContentReferenceStream, monitor);
+ } finally {
+ try {
+ localContentReferenceStream.close();
+ } catch (IOException e){}
+ }
+ }
+ result = localFile.toURL();
+ return result;
+ }
+
+ /*
+ * [20305] need to slam permissions for executable libs on some
+ * platforms. This is a temporary fix
+ */
+ public static void checkPermissions(ContentReference ref, String filePath) {
+
+ if (ref.getPermission() != 0) {
+ UpdateCore.warn("Change permission for " + filePath + " to " + ref.getPermission()); //$NON-NLS-1$ //$NON-NLS-2$
+ // FIXME: change the code to use JNI
+ }
+
+ if (filePath != null && OS_UNIX && ref.getPermission() != 0) {
+ // add execute permission on shared libraries 20305
+ // do not remove write permission 20896
+ // chmod a+x *.sl
+ try {
+ Process pr = Runtime.getRuntime().exec(new String[] { "chmod", "a+x", filePath }); //$NON-NLS-1$ //$NON-NLS-2$
+ Thread chmodOutput = new StreamConsumer(pr.getInputStream());
+ chmodOutput.setName("chmod output reader"); //$NON-NLS-1$
+ chmodOutput.start();
+ Thread chmodError = new StreamConsumer(pr.getErrorStream());
+ chmodError.setName("chmod error reader"); //$NON-NLS-1$
+ chmodError.start();
+ } catch (IOException ioe) {
+ }
+
+ }
+ }
+
+ /**
+ * Returns a random file name for the local system
+ * attempt to conserve the extension if there is a '.' in the path
+ * and no File.Seperator after the '.'
+ *
+ * \a\b\c.txt -> c987659385.txt
+ * c.txt -> c3854763.txt
+ * c -> c953867549
+ */
+ public static String getLocalRandomIdentifier(String remotePath, Date date) {
+ int dotIndex = remotePath.lastIndexOf("."); //$NON-NLS-1$
+ int fileIndex = remotePath.lastIndexOf(File.separator);
+ // if there is a separator after the dot
+ // do not consider it as an extension
+ String ext = (dotIndex != -1 && fileIndex < dotIndex) ? remotePath.substring(dotIndex) : ""; //$NON-NLS-1$
+ // the name is the string between the separator and the dot
+ // if there is no separator, it is the string up to the dot
+ // if there is no dot, go to the end of the string
+ if (fileIndex == -1)
+ fileIndex = 0;
+ if (dotIndex == -1)
+ dotIndex = remotePath.length();
+ // if I have a separator and no dot: /a/b/c -> c
+ // if my separator is the last /a/b/c/, fileIndex and dotIndex are the same, so it will return the default temp name
+ String name = (fileIndex < dotIndex) ? remotePath.substring(fileIndex, dotIndex) : "Eclipse_Update_TMP_"; //$NON-NLS-1$
+ String result = name + date.getTime() + ext;
+ return result;
+ }
+
+ /**
+ * remove a file or directory from the file system.
+ * used to clean up install
+ */
+ public static void removeFromFileSystem(File file) {
+ if (!file.exists() || !file.canWrite())
+ return;
+
+ if (file.isDirectory()) {
+ String[] files = file.list();
+ if (files != null) // be careful since file.list() can return null
+ for (int i = 0; i < files.length; ++i)
+ removeFromFileSystem(new File(file, files[i]));
+ }
+
+ if (!file.delete()) {
+ String msg = NLS.bind(Messages.UpdateManagerUtils_UnableToRemoveFile, (new String[] { file.getAbsolutePath() }));
+ UpdateCore.log(msg, new Exception());
+ }
+ }
+
+ /**
+ * remove all the empty directories recursively
+ * used to clean up install
+ */
+ public static void removeEmptyDirectoriesFromFileSystem(File file) {
+ if (!file.isDirectory())
+ return;
+
+ String[] files = file.list();
+ if (files != null) { // be careful since file.list() can return null
+ for (int i = 0; i < files.length; ++i) {
+ removeEmptyDirectoriesFromFileSystem(new File(file, files[i]));
+ }
+ }
+ if (!file.delete()) {
+ String msg = NLS.bind(Messages.UpdateManagerUtils_UnableToRemoveFile, (new String[] { file.getAbsolutePath() }));
+ UpdateCore.log(msg, new Exception());
+ }
+ }
+
+ /**
+ * Returns the plugin entries that are in source array and
+ * not in target array
+ */
+ public static IPluginEntry[] diff(IPluginEntry[] sourceArray, IPluginEntry[] targetArray) { // No pluginEntry to Install, return Nothing to instal
+ if (sourceArray == null || sourceArray.length == 0) {
+ return new IPluginEntry[0];
+ } // No pluginEntry installed, Install them all
+ if (targetArray == null || targetArray.length == 0) {
+ return sourceArray;
+ } // if a IPluginEntry from sourceArray is NOT in
+ // targetArray, add it to the list
+ List list1 = Arrays.asList(targetArray);
+ List result = new ArrayList(0);
+ for (int i = 0; i < sourceArray.length; i++) {
+ if (!list1.contains(sourceArray[i]))
+ result.add(sourceArray[i]);
+ }
+
+ IPluginEntry[] resultEntry = new IPluginEntry[result.size()];
+ if (result.size() > 0)
+ result.toArray(resultEntry);
+ return resultEntry;
+ }
+
+ /**
+ *
+ */
+ public static URL asDirectoryURL(URL url) throws MalformedURLException {
+ //url = URLEncoder.encode(url);
+ String path = url.getFile();
+ if (!path.endsWith("/")) { //$NON-NLS-1$
+ int index = path.lastIndexOf('/');
+ if (index != -1)
+ path = path.substring(0, index + 1);
+ // ignore any ref in original URL
+ url = new URL(url.getProtocol(), url.getHost(), url.getPort(), path);
+ }
+ return url;
+ }
+
+ /*
+ * Compares two URL for equality
+ * Return false if one of them is null
+ */
+ public static boolean sameURL(URL url1, URL url2) {
+
+ if (url1 == null || url2 == null)
+ return false;
+ if (url1 == url2)
+ return true;
+ if (url1.equals(url2))
+ return true;
+
+ // check if URL are file: URL as we may
+ // have 2 URL pointing to the same featureReference
+ // but with different representation
+ // (i.e. file:/C;/ and file:C:/)
+ if (!"file".equalsIgnoreCase(url1.getProtocol())) //$NON-NLS-1$
+ return false;
+ if (!"file".equalsIgnoreCase(url2.getProtocol())) //$NON-NLS-1$
+ return false;
+
+ File file1 = getFileFor(url1);//new File(url1.getFile());
+ File file2 = getFileFor(url2);
+
+ if (file1 == null)
+ return false;
+
+ return (file1.equals(file2));
+ }
+
+ /*
+ * Method getFileFor.
+ * @param url1
+ * @return File
+ */
+ private static File getFileFor(URL url1) {
+ if (urlFileMap == null) urlFileMap = new HashMap();
+ if (urlFileMap.get(url1)!=null) return (File)urlFileMap.get(url1);
+ File newFile = new File(url1.getFile());
+ urlFileMap.put(url1,newFile);
+ return newFile;
+ }
+
+ /*
+ * returns the list of FeatureReference that are parent of
+ * the Feature or an empty array if no parent found.
+ * @param onlyOptional if set to <code>true</code> only return parents that consider the feature optional
+ * @param child
+ * @param possiblesParent
+ */
+ public static IFeatureReference[] getParentFeatures(IFeature childFeature, IFeatureReference[] possiblesParent, boolean onlyOptional) throws CoreException {
+
+ if (childFeature == null)
+ return new IFeatureReference[0];
+
+ List parentList = new ArrayList();
+ IIncludedFeatureReference[] children = null;
+ IFeature compareFeature = null;
+ for (int i = 0; i < possiblesParent.length; i++) {
+ try {
+ IFeature possibleParentFeature = possiblesParent[i].getFeature(null);
+ if (possibleParentFeature != null) {
+ children = possibleParentFeature.getIncludedFeatureReferences();
+ for (int j = 0; j < children.length; j++) {
+ try {
+ compareFeature = children[j].getFeature(null);
+ } catch (CoreException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+ if (childFeature.equals(compareFeature)) {
+ if (onlyOptional) {
+ if (UpdateManagerUtils.isOptional(children[j])) {
+ parentList.add(possiblesParent[i]);
+ } else {
+ UpdateCore.warn("Feature :" + children[j] + " not optional. Not included in parents list."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ } else {
+ parentList.add(possiblesParent[i]);
+ }
+ }
+ }
+ }
+ } catch (CoreException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+ }
+
+ IFeatureReference[] parents = new IFeatureReference[0];
+ if (parentList.size() > 0) {
+ parents = new IFeatureReference[parentList.size()];
+ parentList.toArray(parents);
+ }
+ return parents;
+ }
+
+ /*
+ * If the return code of the HTTP connection is not 200 (OK)
+ * thow an IO exception
+ *
+ */
+ public static void checkConnectionResult(IResponse response,URL url) throws IOException {
+ // did the server return an error code ?
+ int result = response.getStatusCode();
+
+ if (result != UpdateCore.HTTP_OK) {
+ String serverMsg = response.getStatusMessage();
+ response.close();
+ throw new FatalIOException(NLS.bind(Messages.ContentReference_HttpNok, (new Object[] { new Integer(result), serverMsg, url })));
+ }
+ }
+
+ public static class StreamConsumer extends Thread {
+ InputStream is;
+ byte[] buf;
+ public StreamConsumer(InputStream inputStream) {
+ super();
+ this.setDaemon(true);
+ this.is = inputStream;
+ buf = new byte[512];
+ }
+ public void run() {
+ try {
+ int n = 0;
+ while (n >= 0)
+ n = is.read(buf);
+ } catch (IOException ioe) {
+ }
+ }
+ }
+
+ /**
+ * Return the optional children to install
+ * The optional features to install may not all be direct children
+ * of the feature.
+ * Also include non-optional features
+ *
+ * @param children all the nested features
+ * @param optionalfeatures optional features to install
+ * @return IFeatureReference[]
+ */
+ public static IFeatureReference[] optionalChildrenToInstall(IFeatureReference[] children, IFeatureReference[] optionalfeatures) {
+
+ List optionalChildrenToInstall = new ArrayList();
+ for (int i = 0; i < children.length; i++) {
+ IFeatureReference optionalFeature = children[i];
+ if (!UpdateManagerUtils.isOptional(optionalFeature)) {
+ optionalChildrenToInstall.add(optionalFeature);
+ } else {
+ for (int j = 0; j < optionalfeatures.length; j++) {
+ if (optionalFeature.equals(optionalfeatures[j])) {
+ optionalChildrenToInstall.add(optionalFeature);
+ break;
+ }
+ }
+ }
+ }
+
+ IFeatureReference[] result = new IFeatureReference[optionalChildrenToInstall.size()];
+ if (optionalChildrenToInstall.size() > 0) {
+ optionalChildrenToInstall.toArray(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * returns the mapping of matching rules
+ * the default returns perfect
+ *
+ * @since 2.0.2
+ */
+ public static int getMatchingRule(String rule) {
+ if (rule == null)
+ return IUpdateConstants.RULE_COMPATIBLE;
+ final Integer integer = (Integer) table.get(rule);
+ if (integer == null)
+ return IUpdateConstants.RULE_PERFECT;
+ int ruleInt = integer.intValue();
+ if (ruleInt == IUpdateConstants.RULE_NONE)
+ return IUpdateConstants.RULE_PERFECT;
+ return ruleInt;
+ }
+
+ /**
+ * returns the mapping of matching id rules
+ * the default returns perfect
+ *
+ * @since 2.0.2
+ */
+ public static int getMatchingIdRule(String rule) {
+
+ if (rule == null)
+ return IUpdateConstants.RULE_COMPATIBLE;
+ if (rule!=null && rule.equalsIgnoreCase("prefix")) //$NON-NLS-1$
+ return IUpdateConstants.RULE_PREFIX;
+ return IUpdateConstants.RULE_PERFECT;
+ }
+
+ /**
+ * Method isOptional.
+ * @param featureReference
+ * @return boolean
+ */
+ public static boolean isOptional(IFeatureReference featureReference) {
+ if (featureReference==null) return false;
+ if (featureReference instanceof IIncludedFeatureReference){
+ return ((IIncludedFeatureReference)featureReference).isOptional();
+ }
+ return false;
+ }
+
+ /**
+ *
+ */
+ public static boolean isValidEnvironment(IPlatformEnvironment candidate) {
+ if (candidate==null) return false;
+ String os = candidate.getOS();
+ String ws = candidate.getWS();
+ String arch = candidate.getOSArch();
+ String nl = candidate.getNL();
+ if (os!=null && !isMatching(os, SiteManager.getOS())) return false;
+ if (ws!=null && !isMatching(ws, SiteManager.getWS())) return false;
+ if (arch!=null && !isMatching(arch, SiteManager.getOSArch())) return false;
+ if (nl!=null && !isMatchingLocale(nl, SiteManager.getNL())) return false;
+ return true;
+ }
+
+ /* Original code - commented out to provide a replacement as per bug 98387
+
+ private static boolean isMatching(String candidateValues, String siteValues) {
+ if (siteValues==null) return false;
+ if ("*".equals(candidateValues)) return true; //$NON-NLS-1$
+ if ("".equals(candidateValues)) return true; //$NON-NLS-1$
+ siteValues = siteValues.toUpperCase();
+ StringTokenizer stok = new StringTokenizer(candidateValues, ","); //$NON-NLS-1$
+ while (stok.hasMoreTokens()) {
+ String token = stok.nextToken().toUpperCase();
+ if (siteValues.indexOf(token)!=-1) return true;
+ }
+ return false;
+ }
+ */
+
+ /*
+ * Fixed bug 98387
+ */
+
+ private static boolean isMatching(String candidateValues, String siteValues) {
+ if (siteValues==null) return false;
+ if ("*".equals(candidateValues)) return true; //$NON-NLS-1$
+ if ("".equals(candidateValues)) return true; //$NON-NLS-1$
+ StringTokenizer siteTokens = new StringTokenizer(siteValues, ","); //$NON-NLS-1$
+ //$NON-NLS-1$
+ while(siteTokens.hasMoreTokens()) {
+ StringTokenizer candidateTokens = new StringTokenizer
+ (candidateValues, ","); //$NON-NLS-1$
+ String siteValue = siteTokens.nextToken();
+ while (candidateTokens.hasMoreTokens()) {
+ if (siteValue.equalsIgnoreCase
+ (candidateTokens.nextToken())) return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ *
+ */
+ private static boolean isMatchingLocale(String candidateValues, String locale) {
+ if (locale==null) return false;
+ if ("*".equals(candidateValues)) return true; //$NON-NLS-1$
+ if ("".equals(candidateValues)) return true; //$NON-NLS-1$
+
+ locale = locale.toUpperCase();
+ candidateValues = candidateValues.toUpperCase();
+ StringTokenizer stok = new StringTokenizer(candidateValues, ","); //$NON-NLS-1$
+ while (stok.hasMoreTokens()) {
+ String candidate = stok.nextToken();
+ if (locale.indexOf(candidate) == 0)
+ return true;
+ if (candidate.indexOf(locale) == 0)
+ return true;
+ }
+ return false;
+ }
+
+
+ /*
+ *
+ */
+ private static void appendEscapedChar(StringBuffer buffer, char c) {
+ String replacement = getReplacement(c);
+ if (replacement != null) {
+ buffer.append('&');
+ buffer.append(replacement);
+ buffer.append(';');
+ } else {
+ if ((c >= ' ' && c <= 0x7E) || c == '\n' || c == '\r' || c == '\t') {
+ buffer.append(c);
+ } else {
+ buffer.append("&#"); //$NON-NLS-1$
+ buffer.append(Integer.toString(c));
+ buffer.append(';');
+ }
+ }
+ }
+
+ /*
+ *
+ */
+ public static String xmlSafe(String s) {
+ StringBuffer result = new StringBuffer(s.length() + 10);
+ for (int i = 0; i < s.length(); ++i)
+ appendEscapedChar(result, s.charAt(i));
+ return result.toString();
+ }
+
+ /*
+ *
+ */
+ private static String getReplacement(char c) {
+ // Encode special XML characters into the equivalent character references.
+ // These five are defined by default for all XML documents.
+ switch (c) {
+ case '<' :
+ return "lt"; //$NON-NLS-1$
+ case '>' :
+ return "gt"; //$NON-NLS-1$
+ case '"' :
+ return "quot"; //$NON-NLS-1$
+ case '\'' :
+ return "apos"; //$NON-NLS-1$
+ case '&' :
+ return "amp"; //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ public static boolean isSameTimestamp(URL url, long timestamp) {
+ try {
+ if (UpdateCore.getPlugin().getUpdateSession().isVisited(url)) {
+ return true;
+ }
+ URL resolvedURL = URLEncoder.encode(url);
+ IResponse response = ConnectionFactory.get(resolvedURL);
+ long remoteLastModified = response.getLastModified();
+ // 2 seconds tolerance, as some OS's may round up the time stamp
+ // to the closest second. For safety, we make it 2 seconds.
+ return Math.abs(remoteLastModified - timestamp)/1000 <= 2;
+ } catch (MalformedURLException e) {
+ return false;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ /**
+ * The file is associated with a lookup key.
+ * @param key optional lookup key, or <code>null</code>.
+ * @param temp the local working file
+ */
+ public synchronized static void mapLocalFileFragment(String key, FileFragment temp) {
+ // create file association
+ if (key != null) {
+ if (localFileFragmentMap == null)
+ localFileFragmentMap = new HashMap();
+ localFileFragmentMap.put(key, temp);
+ }
+ }
+
+ /**
+ * The file is associated with a lookup key.
+ * @param key optional lookup key, or <code>null</code>.
+ */
+ public synchronized static void unMapLocalFileFragment(String key) {
+ // remove file association
+ if (key != null && localFileFragmentMap !=null) {
+ localFileFragmentMap.remove(key);
+ }
+ }
+
+ /**
+ * Returns a previously cached local file (in temporary area) matching the
+ * specified key.
+ *
+ * @param key lookup key
+ * @return cached file, or <code>null</code>.
+ */
+ public static synchronized FileFragment lookupLocalFileFragment(String key) {
+ if (localFileFragmentMap == null)
+ return null;
+ return (FileFragment) localFileFragmentMap.get(key);
+ }
+
+ /**
+ * Copies specified input stream to the output stream. Neither stream
+ * is closed as part of this operation.
+ *
+ * @param is input stream
+ * @param os output stream
+ * @param monitor progress monitor
+ * @param expectedLength - if > 0, the number of bytes from InputStream will be verified
+ * @@return the offset in the input stream where copying stopped. Returns -1 if end of input stream is reached.
+ * @since 2.0
+ */
+ public static long copy(InputStream is, OutputStream os, InstallMonitor monitor, long expectedLength) {
+ byte[] buf = getBuffer();
+ long offset=0;
+ try {
+ int len = is.read(buf);
+ int nextIncrement = 0;
+ while (len != -1) {
+ os.write(buf, 0, len);
+ offset += len;
+ if (monitor != null) {
+ nextIncrement += len;
+ // update monitor periodically
+ if (nextIncrement >= INCREMENT_SIZE){
+ monitor.incrementCount(nextIncrement);
+ nextIncrement = 0;
+ }
+ if (monitor.isCanceled()) {
+ return offset;
+ }
+ }
+ if (expectedLength > 0 && offset == expectedLength) {
+ // everything read do not return offset, otherwise trying
+ // to read again from this offset will result in HTTP 416
+ break;
+ }
+
+ len = is.read(buf);
+ }
+ if (nextIncrement > 0 && monitor != null)
+ monitor.incrementCount(nextIncrement);
+ if(expectedLength>0 && offset!=expectedLength)
+ throw new IOException(NLS.bind(Messages.UpdateManagerUtils_inputStreamEnded, (new String[] { String.valueOf(offset), String.valueOf(expectedLength) })));
+ return -1;
+ } catch(IOException e){
+ // Log the actual error, as this is no longer
+ // passed up the calling stack
+ UpdateCore.log(Messages.UpdateManagerUtils_copy + offset, e);
+ return offset;
+ } finally {
+ freeBuffer(buf);
+ }
+ }
+
+ private static synchronized byte[] getBuffer() {
+ if (bufferPool == null) {
+ return new byte[BUFFER_SIZE];
+ }
+
+ try {
+ return (byte[]) bufferPool.pop();
+ } catch (EmptyStackException e) {
+ return new byte[BUFFER_SIZE];
+ }
+ }
+
+ private static synchronized void freeBuffer(byte[] buf) {
+ if (bufferPool == null)
+ bufferPool = new Stack();
+ bufferPool.push(buf);
+ }
+
+
+ /**
+ * Returns a list of fragments. Zero length if no fragments.
+ * @param bundle the bundle to get fragments for
+ */
+ public static FragmentEntry[] getFragments(Bundle bundle) {
+ PackageAdmin pkgAdmin = UpdateCore.getPlugin().getPackageAdmin();
+ Bundle[] fragmentBundles = pkgAdmin.getFragments(bundle);
+ if (fragmentBundles == null)
+ return noFragments;
+
+ FragmentEntry[] fragments = new FragmentEntry[fragmentBundles.length];
+ for (int i = 0; i < fragments.length; i++) {
+ fragments[i] = new FragmentEntry((String) fragmentBundles[i]
+ .getHeaders().get(Constants.BUNDLE_SYMBOLICNAME),
+ (String) fragmentBundles[i].getHeaders().get(
+ Constants.BUNDLE_VERSION), Platform
+ .getResourceString(fragmentBundles[i],
+ (String) fragmentBundles[i].getHeaders()
+ .get(Constants.BUNDLE_VERSION)),
+ fragmentBundles[i].getLocation());
+ }
+ return fragments;
+ }
+
+ public static String getWritableXMLString(String value) {
+ StringBuffer buf = new StringBuffer();
+ if(value == null)
+ return buf.toString();
+ for (int i = 0; i < value.length(); i++) {
+ char c = value.charAt(i);
+ switch (c) {
+ case '&' :
+ buf.append("&"); //$NON-NLS-1$
+ break;
+ case '<' :
+ buf.append("<"); //$NON-NLS-1$
+ break;
+ case '>' :
+ buf.append(">"); //$NON-NLS-1$
+ break;
+ case '\'' :
+ buf.append("'"); //$NON-NLS-1$
+ break;
+ case '\"' :
+ buf.append("""); //$NON-NLS-1$
+ break;
+ case 0x00 :
+ buf.append(" "); //$NON-NLS-1$
+ break;
+ default :
+ buf.append(c);
+ break;
+ }
+ }
+ return buf.toString();
+ }
+
+ public static LiteFeature[] getLightFeatures(ExtendedSite site) {
+
+ URL fullDigestURL;
+ try {
+ fullDigestURL = getFullDigestURL( site, Locale.getDefault().getCountry(), Locale.getDefault().getLanguage());
+ } catch (MalformedURLException e) {
+ UpdateCore.log("Could not access digest on the site: " + e.getMessage(), null); //$NON-NLS-1$
+ return null;
+ }
+
+ Digest digest = new Digest( fullDigestURL);
+ try {
+ LiteFeature[] features = (LiteFeature[])digest.parseDigest();
+ for(int i = 0; i < features.length; i++) {
+ features[i].setSite(site);
+ }
+ return features;
+ } catch(Exception e){
+ UpdateCore.log("Digest could not be parsed:" + e.getMessage(), null); //$NON-NLS-1$
+ return null;
+ }
+ }
+
+ private static URL getFullDigestURL(ExtendedSite site, String country, String language) throws MalformedURLException {
+
+ String digestURL = (site.getDigestURL().endsWith("/")? site.getDigestURL(): site.getDigestURL() + "/"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ if (digestURL.indexOf("://") == -1) { //$NON-NLS-1$
+ String siteURL = site.getLocationURL().toExternalForm();
+ if (siteURL.endsWith(Site.SITE_XML)) {
+ siteURL = siteURL.substring(0, siteURL.length() - Site.SITE_XML.length());
+ }
+ if (digestURL.equals("/")) { //$NON-NLS-1$
+ digestURL = siteURL;
+ } else {
+ if (digestURL.startsWith("/")) { //$NON-NLS-1$
+ digestURL = digestURL.substring(1, digestURL.length());
+ }
+ digestURL = siteURL + digestURL;
+ }
+ }
+
+ digestURL += "digest"; //$NON-NLS-1$
+
+ if ( isLocalSupported(site, country, language)) {
+ return new URL(digestURL + "_" + language + "_" + country + ".zip"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ( isLangaugeSupported(site, language)) {
+ return new URL(digestURL + "_" + language + ".zip"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return new URL(digestURL + ".zip"); //$NON-NLS-1$
+ }
+
+ private static boolean isLangaugeSupported(ExtendedSite site, String language) {
+ String[] availableLanguages = site.getAvailableLocals();
+ if ((availableLanguages == null) || (availableLanguages.length == 0)) {
+ return false;
+ }
+ for(int i = 0; i < availableLanguages.length; i++) {
+ if (availableLanguages[i].equals(language)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isLocalSupported(ExtendedSite site, String country, String language) {
+ String localeCode = language + "_" + country; //$NON-NLS-1$
+ String[] availableLocals = site.getAvailableLocals();
+ if ((availableLocals == null) || (availableLocals.length == 0)) {
+ return false;
+ }
+ for(int i = 0; i < availableLocals.length; i++) {
+ if (availableLocals[i].equals(localeCode)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdatePreferencesInitializer.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdatePreferencesInitializer.java
new file mode 100644
index 0000000..3d5a5db
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdatePreferencesInitializer.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2007 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.update.internal.core;
+
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+
+/**
+ * Class to initialize the preferences for the Update core plugin.
+ */
+public class UpdatePreferencesInitializer extends AbstractPreferenceInitializer {
+
+ /**
+ * Default constructor
+ */
+ public UpdatePreferencesInitializer() {
+ super();
+ }
+
+ /**
+ * Initializes the default preferences settings for this plug-in.
+ * <p>
+ * This method is called sometime after the preference store for this
+ * plug-in is created. Default values are never stored in preference
+ * stores; they must be filled in each time. This method provides the
+ * opportunity to initialize the default values.
+ * </p>
+ * <p>
+ * The default implementation of this method does nothing. A subclass that needs
+ * to set default values for its preferences must reimplement this method.
+ * Default values set at a later point will override any default override
+ * settings supplied from outside the plug-in (product configuration or
+ * platform start up).
+ * </p>
+ */
+ public void initializeDefaultPreferences() {
+ Plugin plugin = UpdateCore.getPlugin();
+ plugin.getPluginPreferences().setDefault(UpdateCore.P_CHECK_SIGNATURE, true);
+ plugin.getPluginPreferences().setDefault(UpdateCore.P_AUTOMATICALLY_CHOOSE_MIRROR, false);
+ plugin.getPluginPreferences().setDefault(UpdateCore.P_HISTORY_SIZE, UpdateCore.DEFAULT_HISTORY);
+ plugin.getPluginPreferences().setDefault(UpdateCore.P_UPDATE_VERSIONS, UpdateCore.EQUIVALENT_VALUE);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateSession.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateSession.java
new file mode 100644
index 0000000..9b2cb64
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateSession.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 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 - Initial API and implementation
+ * James D Miles (IBM Corp.) - bug 191783, NullPointerException in FeatureDownloader
+ *******************************************************************************/
+
+package org.eclipse.update.internal.core;
+
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class UpdateSession {
+
+ private boolean enabled = false;
+ private Set visitedURLs = Collections.synchronizedSet(new HashSet());
+
+ UpdateSession() {
+ }
+
+ public boolean isVisited(URL url) {
+ if (!enabled)
+ return false;
+ return visitedURLs.contains(url.toExternalForm());
+ }
+
+ public void markVisited(URL url) {
+ if (!enabled)
+ return ;
+ visitedURLs.add(url.toExternalForm());
+ }
+
+ /*
+ * Session will not start caching URLs prior to calling this
+ * method. If you want to use update session facility make sure
+ * you call this method first
+ */
+ public void reset() {
+ this.enabled = true;
+ visitedURLs.clear();
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateSiteFeatureReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateSiteFeatureReference.java
new file mode 100644
index 0000000..1a906a5
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateSiteFeatureReference.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+
+import org.eclipse.update.core.*;
+
+/**
+ * Feature reference on an update site.
+ * @since 3.1
+ */
+public class UpdateSiteFeatureReference extends SiteFeatureReference {
+ private String os;
+ private String ws;
+ private String nl;
+ private String arch;
+ private String patch;
+
+ /**
+ * Get optional operating system specification as a comma-separated string.
+ *
+ * @return the operating system specification string, or <code>null</code>.
+ * @since 3.1
+ */
+ public String getOS() {
+ return os;
+ }
+
+
+ /**
+ * Get optional windowing system specification as a comma-separated string.
+ *
+ * @return the windowing system specification string, or <code>null</code>.
+ * @since 3.1
+ */
+ public String getWS() {
+ return ws;
+ }
+
+
+ /**
+ * Get optional system architecture specification as a comma-separated string.
+ *
+ * @return the system architecture specification string, or <code>null</code>.
+ * @since 3.1
+ */
+ public String getOSArch() {
+ return arch;
+ }
+
+
+ /**
+ * Get optional locale specification as a comma-separated string.
+ *
+ * @return the locale specification string, or <code>null</code>.
+ * @since 3.1
+ */
+ public String getNL() {
+ return nl;
+ }
+
+ /**
+ * Sets the operating system specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param os operating system specification as a comma-separated list
+ * @since 3.1
+ */
+ public void setOS(String os) {
+ assertIsWriteable();
+ this.os = os;
+ }
+
+
+ /**
+ * Sets the windowing system specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param ws windowing system specification as a comma-separated list
+ * @since 3.1
+ */
+ public void setWS(String ws) {
+ assertIsWriteable();
+ this.ws = ws;
+ }
+
+
+ /**
+ * Sets the locale specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param nl locale specification as a comma-separated list
+ * @since 3.1
+ */
+ public void setNL(String nl) {
+ assertIsWriteable();
+ this.nl = nl;
+ }
+
+
+ /**
+ * Sets the system architecture specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param arch system architecture specification as a comma-separated list
+ * @since 3.1
+ */
+ public void setArch(String arch) {
+ assertIsWriteable();
+ this.arch = arch;
+ }
+
+ /**
+ * Returns the patch mode.
+ * @since 3.1
+ */
+ public String getPatch() {
+ return patch;
+ }
+
+
+ /**
+ * Sets the patch mode.
+ * @since 3.1
+ */
+ public void setPatch(String patch) {
+ this.patch = patch;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateSiteIncludedFeatureReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateSiteIncludedFeatureReference.java
new file mode 100644
index 0000000..372d74f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateSiteIncludedFeatureReference.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+
+import org.eclipse.update.core.*;
+
+/**
+ * Feature reference on an update site.
+ * @since 3.1
+ */
+public class UpdateSiteIncludedFeatureReference extends IncludedFeatureReference{
+ private String os;
+ private String ws;
+ private String nl;
+ private String arch;
+ private String patch;
+
+ public UpdateSiteIncludedFeatureReference() {
+ super();
+ }
+
+ public UpdateSiteIncludedFeatureReference(IIncludedFeatureReference include) {
+ super(include);
+ }
+
+
+ /**
+ * Get optional operating system specification as a comma-separated string.
+ *
+ * @return the operating system specification string, or <code>null</code>.
+ * @since 3.1
+ */
+ public String getOS() {
+ return os;
+ }
+
+
+ /**
+ * Get optional windowing system specification as a comma-separated string.
+ *
+ * @return the windowing system specification string, or <code>null</code>.
+ * @since 3.1
+ */
+ public String getWS() {
+ return ws;
+ }
+
+
+ /**
+ * Get optional system architecture specification as a comma-separated string.
+ *
+ * @return the system architecture specification string, or <code>null</code>.
+ * @since 3.1
+ */
+ public String getOSArch() {
+ return arch;
+ }
+
+
+ /**
+ * Get optional locale specification as a comma-separated string.
+ *
+ * @return the locale specification string, or <code>null</code>.
+ * @since 3.1
+ */
+ public String getNL() {
+ return nl;
+ }
+
+ /**
+ * Sets the operating system specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param os operating system specification as a comma-separated list
+ * @since 3.1
+ */
+ public void setOS(String os) {
+ assertIsWriteable();
+ this.os = os;
+ }
+
+
+ /**
+ * Sets the windowing system specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param ws windowing system specification as a comma-separated list
+ * @since 3.1
+ */
+ public void setWS(String ws) {
+ assertIsWriteable();
+ this.ws = ws;
+ }
+
+
+ /**
+ * Sets the locale specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param nl locale specification as a comma-separated list
+ * @since 3.1
+ */
+ public void setNL(String nl) {
+ assertIsWriteable();
+ this.nl = nl;
+ }
+
+
+ /**
+ * Sets the system architecture specification.
+ * Throws a runtime exception if this object is marked read-only.
+ *
+ * @param arch system architecture specification as a comma-separated list
+ * @since 3.1
+ */
+ public void setArch(String arch) {
+ assertIsWriteable();
+ this.arch = arch;
+ }
+
+ /**
+ * Returns the patch mode.
+ * @since 3.1
+ */
+ public String getPatch() {
+ return patch;
+ }
+
+
+ /**
+ * Sets the patch mode.
+ * @since 3.1
+ */
+ public void setPatch(String patch) {
+ this.patch = patch;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/Volume.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/Volume.java
new file mode 100644
index 0000000..6bd66de
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/Volume.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core;
+
+import java.io.File;
+
+import org.eclipse.update.configuration.IVolume;
+import org.eclipse.update.core.model.ModelObject;
+
+/**
+ * Default implementation of a IVolume
+ */
+public class Volume extends ModelObject implements IVolume {
+
+ private long size;
+ private int type;
+ private String label;
+ private File root;
+
+ /**
+ * Constructor for Volume.
+ */
+ public Volume(File root,String label,int type,long size) {
+ super();
+ this.root = root;
+ this.label = label;
+ this.type = type;
+ this.size = size;
+ }
+
+ /**
+ * @see IVolume#getFreeSpace()
+ */
+ public long getFreeSpace() {
+ return size;
+ }
+
+ /**
+ * @see IVolume#getLabel()
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * @see IVolume#getType()
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * @see IVolume#getFile()
+ */
+ public File getFile() {
+ return root;
+ }
+
+ public Object getAdapter(Class arg0) {
+ return null;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/AbstractResponse.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/AbstractResponse.java
new file mode 100644
index 0000000..c82bb32
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/AbstractResponse.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 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.update.internal.core.connection;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLConnection;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.update.internal.core.UpdateCore;
+
+/**
+ * @author btripkov
+ *
+ */
+public abstract class AbstractResponse implements IResponse {
+
+ private static final long POLLING_INTERVAL = 200;
+ protected URLConnection connection;
+
+ protected InputStream openStreamWithCancel(URLConnection urlConnection, IProgressMonitor monitor) throws IOException, CoreException, TooManyOpenConnectionsException {
+
+ ConnectionThreadManager.StreamRunnable runnable =
+ new ConnectionThreadManager.StreamRunnable(urlConnection);
+ Thread t = ConnectionThreadManagerFactory.getConnectionManager().getConnectionThread(
+ runnable);
+ t.start();
+ InputStream is = null;
+ try {
+ for (;;) {
+ if (monitor.isCanceled()) {
+ runnable.disconnect();
+ connection = null;
+ break;
+ }
+ if (runnable.getInputStream() != null || !t.isAlive()) {
+ is = runnable.getInputStream();
+ break;
+ }
+ if (runnable.getIOException() != null)
+ throw runnable.getIOException();
+ if (runnable.getException() != null)
+ throw new CoreException(new Status(IStatus.ERROR,
+ UpdateCore.getPlugin().getBundle().getSymbolicName(),
+ IStatus.OK,
+ runnable.getException().getMessage(),
+ runnable.getException()));
+ t.join(POLLING_INTERVAL);
+ }
+ } catch (InterruptedException e) {
+ }
+ return is;
+ }
+
+
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/ConnectionFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/ConnectionFactory.java
new file mode 100644
index 0000000..6c2e3e0
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/ConnectionFactory.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core.connection;
+
+import java.io.IOException;
+import java.net.URL;
+
+public class ConnectionFactory {
+
+
+ public static IResponse get(URL url) throws IOException {
+ //Request request = null;
+ IResponse response = null;
+
+ if ("file".equals(url.getProtocol())) { //$NON-NLS-1$
+ response = new FileResponse(url);
+ } else if (url != null && url.getProtocol().startsWith("http")) { //$NON-NLS-1$
+ response = new HttpResponse(url);
+ } else {
+ response = new OtherResponse(url);
+ }
+
+ return response;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/ConnectionThreadManager.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/ConnectionThreadManager.java
new file mode 100644
index 0000000..d747cac
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/ConnectionThreadManager.java
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.core.connection;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+
+/**
+ * This class manages threads that are dispatched to
+ * obtained a valid input stream from an HTTP connection.
+ * Since obtaining an input stream is an I/O operation
+ * that may block for a long time, it is performed
+ * on a separate thread to keep the UI responsive.
+ * <p>
+ * In case that a connection blocks and does not
+ * terminate with an IOException after a timeout,
+ * active threads may accumulate. The manager will
+ * refuse to create more than MAX_COUNT threads and
+ * instead will throw a CoreException with a child
+ * status object for each connection that is still pending.
+ * <p>
+ * If the connection is responsive but slow, the user
+ * may cancel it. In that case, the manager will
+ * close the stream to avoid resource leak.
+ */
+public class ConnectionThreadManager {
+
+ // set connection timeout to 1 minute
+ private static final String CONNECT_TIMEOUT = "60000"; //$NON-NLS-1$
+ // set read timeout to 1 minute
+ private static final String READ_TIMEOUT = "60000"; //$NON-NLS-1$
+ // max number of active threads
+ private static final int MAX_COUNT = 9;
+ private List threads = new ArrayList(MAX_COUNT);
+
+
+
+ public static class StreamRunnable implements Runnable {
+
+ private URLConnection urlConnection;
+ private IOException ioException;
+ private Exception exception;
+ private InputStream is;
+ private boolean disconnected;
+
+ public StreamRunnable(URLConnection urlConnection) {
+ this.urlConnection = urlConnection;
+ }
+
+ public InputStream getInputStream() {
+ return is;
+ }
+
+ public URL getURL() {
+ return urlConnection.getURL();
+ }
+
+ public IOException getIOException() {
+ return ioException;
+ }
+
+ public Exception getException() {
+ return exception;
+ }
+
+ public void disconnect() {
+ if (urlConnection instanceof HttpURLConnection)
+ ((HttpURLConnection)urlConnection).disconnect();
+ disconnected = true;
+ }
+
+ public void run() {
+ try {
+ is = urlConnection.getInputStream();
+ if (disconnected) {
+ // The connection was slow, but returned
+ // a valid input stream. However,
+ // the user canceled the connection
+ // so we must close to avoid
+ // resource leak.
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException ex) {
+ // at this point, we don't care
+ } finally {
+ is = null;
+ }
+ }
+ }
+ } catch (IOException e) {
+ ioException = e;
+ } catch (Exception e) {
+ exception = e;
+ } finally {
+ //threads.
+ }
+ }
+ }
+
+
+ class ConnectionThread extends Thread {
+
+ private StreamRunnable runnable;
+
+ public ConnectionThread(StreamRunnable runnable) {
+ super(runnable, "update-connection"); //$NON-NLS-1$
+ this.runnable = runnable;
+ }
+
+ public StreamRunnable getRunnable() {
+ return runnable;
+ }
+ }
+
+ public ConnectionThreadManager() {
+ // In case we are running Sun's code.
+ setIfNotDefaultProperty("sun.net.client.defaultConnectTimeout", CONNECT_TIMEOUT); //$NON-NLS-1$
+ setIfNotDefaultProperty("sun.net.client.defaultReadTimeout", READ_TIMEOUT); //$NON-NLS-1$
+ }
+
+ private void setIfNotDefaultProperty(String key, String value) {
+ String oldValue = System.getProperty(key);
+ if (oldValue==null || oldValue.equals("-1")) //$NON-NLS-1$
+ System.setProperty(key, value);
+ }
+
+ public Thread getConnectionThread(StreamRunnable runnable) throws CoreException {
+
+ validateExistingThreads();
+
+ //if (threads == null)
+ // threads = new Vector();
+ Thread t = new Thread(runnable);
+ t.setDaemon(true);
+ threads.add(t);
+ return t;
+ }
+
+ /*
+ * Removes threads that are not alive any more from the
+ * list and ensures that there are at most MAX_COUNT threads
+ * still working.
+ */
+ private void validateExistingThreads() throws CoreException {
+
+ if ((threads == null) || (threads.size() == 0))
+ return;
+
+ int aliveCount = purgeTerminatedThreads();
+
+ if (aliveCount > MAX_COUNT) {
+ ArrayList children = new ArrayList();
+ String pluginId =
+ UpdateCore.getPlugin().getBundle().getSymbolicName();
+ for (int i = 0; i < threads.size(); i++) {
+ ConnectionThread t = (ConnectionThread) threads.get(i);
+ String url = t.getRunnable().getURL().toString();
+ IStatus status =
+ new Status(
+ IStatus.ERROR,
+ pluginId,
+ IStatus.OK,
+ NLS.bind(Messages.ConnectionThreadManager_unresponsiveURL, (new String[] { url })),
+ null);
+ children.add(status);
+ }
+ MultiStatus parentStatus =
+ new MultiStatus(
+ pluginId,
+ IStatus.OK,
+ (IStatus[]) children.toArray(new IStatus[children.size()]),
+ Messages.ConnectionThreadManager_tooManyConnections,
+ null);
+ throw new CoreException(parentStatus);
+ }
+ }
+
+ /*
+ * Removes terminated threads from the list and returns
+ * the number of those still active.
+ */
+
+ private int purgeTerminatedThreads() {
+
+ if (threads.size() == 0) {
+ return 0;
+ }
+
+ int aliveCount = 0;
+
+ Object[] array = threads.toArray();
+ for (int i = 0; i < array.length; i++) {
+ Thread t = (Thread) array[i];
+ if (!t.isAlive())
+ threads.remove(t);
+ else
+ aliveCount++;
+ }
+ return aliveCount;
+ }
+
+ public void shutdown() {
+ // We might want to kill the active threads but
+ // this is not really necessary since they are all
+ // daemons and will not prevent JVM to terminate.
+ threads.clear();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/ConnectionThreadManagerFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/ConnectionThreadManagerFactory.java
new file mode 100644
index 0000000..3257ead
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/ConnectionThreadManagerFactory.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core.connection;
+
+public class ConnectionThreadManagerFactory {
+
+
+ //Connection manager
+ private static ConnectionThreadManager connectionManager;
+
+ /**
+ * Returns the manager that manages URL connection threads.
+ */
+ public static ConnectionThreadManager getConnectionManager() {
+
+ if (connectionManager == null)
+ connectionManager = new ConnectionThreadManager();
+ return connectionManager;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/FileResponse.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/FileResponse.java
new file mode 100644
index 0000000..6facd86
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/FileResponse.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.core.connection;
+import org.eclipse.update.internal.core.UpdateCore;
+
+import java.io.*;
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+
+public class FileResponse implements IResponse {
+
+ protected URL url;
+ protected long lastModified;
+
+ protected FileResponse(URL url) {
+ this.url = url;
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return url.openStream();
+ }
+
+ public InputStream getInputStream(IProgressMonitor monitor)
+ throws IOException, CoreException {
+ return getInputStream();
+ }
+
+ public long getContentLength() {
+ return 0;
+ }
+
+ public int getStatusCode() {
+ return UpdateCore.HTTP_OK;
+ }
+
+ public void close() {
+ // nothing to close
+ }
+
+ public String getStatusMessage() {
+ return ""; //$NON-NLS-1$
+ }
+
+ public long getLastModified() {
+ if (lastModified == 0) {
+ File f = new File(url.getFile());
+ if (f.isDirectory())
+ f = new File(f, "site.xml"); //$NON-NLS-1$
+ lastModified = f.lastModified();
+ }
+ return lastModified;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/HttpResponse.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/HttpResponse.java
new file mode 100644
index 0000000..a3cfa3a
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/HttpResponse.java
@@ -0,0 +1,251 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.core.connection;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+
+public class HttpResponse extends AbstractResponse {
+ /**
+ * Monitored InputStream. Upon IOException, discards
+ * connection so it is not reused.
+ *
+ */
+ private class MonitoringInputStream extends FilterInputStream {
+ private URLConnection connection;
+
+ public MonitoringInputStream(InputStream in, URLConnection connection) {
+ super(in);
+ this.connection = connection;
+ }
+
+ public int available() throws IOException {
+ try {
+ return in!=null?super.available():0;
+ } catch (IOException ioe) {
+ connection = null;
+ throw ioe;
+ }
+ }
+
+ public void close() throws IOException {
+ try {
+ if (in!=null)
+ super.close();
+ if (connection instanceof HttpURLConnection) {
+ ((HttpURLConnection)connection).disconnect();
+ }
+ } catch (IOException ioe) {
+ connection = null;
+ throw ioe;
+ }
+ }
+
+ public int read() throws IOException {
+ try {
+ return in!=null?super.read():-1;
+ } catch (IOException ioe) {
+ connection = null;
+ throw ioe;
+ }
+ }
+
+ public synchronized void reset() throws IOException {
+ try {
+ if (in!=null)
+ super.reset();
+ } catch (IOException ioe) {
+ connection = null;
+ throw ioe;
+ }
+ }
+
+ public int read(byte[] b) throws IOException {
+ try {
+ return in!=null?super.read(b):-1;
+ } catch (IOException ioe) {
+ connection = null;
+ throw ioe;
+ }
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ try {
+ return in!=null?super.read(b, off, len):-1;
+ } catch (IOException ioe) {
+ connection = null;
+ throw ioe;
+ }
+ }
+
+ public long skip(long n) throws IOException {
+ try {
+ return in!=null?super.skip(n):0;
+ } catch (IOException ioe) {
+ connection = null;
+ throw ioe;
+ }
+ }
+
+ }
+
+ protected URL url;
+ protected InputStream in;
+ protected long lastModified;
+ protected long offset;
+
+ protected HttpResponse(URL url) {
+
+ this.url = url;
+ }
+
+ public InputStream getInputStream() throws IOException {
+ if (in == null && url != null) {
+ if (connection == null || offset > 0)
+ connection = url.openConnection();
+ if (offset > 0)
+ connection.setRequestProperty("Range", "bytes=" + offset + "-"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ try {
+ in = new MonitoringInputStream(connection.getInputStream(), connection);
+ } catch (IOException ioe) {
+ connection = null;
+ throw ioe;
+ }
+ checkOffset();
+ }
+ return in;
+ }
+
+ public void close() {
+ if( null != in ) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ }
+ in = null;
+ }
+ if (connection!=null) {
+ ((HttpURLConnection)connection).disconnect();
+ connection = null;
+ }
+ }
+
+ /**
+ * @see IResponse#getInputStream(IProgressMonitor)
+ */
+ public InputStream getInputStream(IProgressMonitor monitor)
+ throws IOException, CoreException, TooManyOpenConnectionsException {
+ if (in == null && url != null) {
+ if (connection == null || offset > 0)
+ connection = url.openConnection();
+ if (offset > 0)
+ connection.setRequestProperty("Range", "bytes=" + offset + "-"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ if (monitor != null) {
+ try {
+ this.in = new MonitoringInputStream(openStreamWithCancel(
+ connection, monitor), connection);
+ } catch (IOException ioe) {
+ connection = null;
+ throw ioe;
+ }
+ } else {
+ try {
+ this.in = new MonitoringInputStream(connection
+ .getInputStream(), connection);
+ } catch (IOException ioe) {
+ connection = null;
+ throw ioe;
+ }
+ }
+ // this can also be run inside a monitoring thread, but it is safe
+ // to
+ // just call it now, if the input stream has already been obtained
+ checkOffset();
+ if (connection != null) {
+ this.lastModified = connection.getLastModified();
+ }
+ }
+ return in;
+ }
+
+ public long getContentLength() {
+ if (connection != null)
+ return connection.getContentLength();
+ return 0;
+ }
+
+ public int getStatusCode() {
+ if (connection == null)
+ try {
+ connection = url.openConnection();
+ } catch (IOException e) {
+ }
+ if (connection != null) {
+ try {
+ return ((HttpURLConnection) connection).getResponseCode();
+ } catch (IOException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+ }
+ return UpdateCore.HTTP_OK;
+ }
+
+ public String getStatusMessage() {
+ if (connection != null) {
+ try {
+ return ((HttpURLConnection) connection).getResponseMessage();
+ } catch (IOException e) {
+ UpdateCore.warn("", e); //$NON-NLS-1$
+ }
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ public long getLastModified() {
+ if (lastModified == 0) {
+ if (connection == null)
+ try {
+ connection = url.openConnection();
+ } catch (IOException e) {
+ }
+ if (connection != null)
+ lastModified = connection.getLastModified();
+ }
+ return lastModified;
+ }
+
+ public void setOffset(long offset) {
+ this.offset = offset;
+ }
+ private void checkOffset() throws IOException {
+ if (offset == 0)
+ return;
+ String range = connection.getHeaderField("Content-Range"); //$NON-NLS-1$
+ //System.out.println("Content-Range=" + range);
+ if (range == null) {
+ //System.err.println("Server does not support ranges");
+ throw new IOException(Messages.HttpResponse_rangeExpected);
+ } else if (!range.startsWith("bytes " + offset + "-")) { //$NON-NLS-1$ //$NON-NLS-2$
+ //System.err.println("Server returned wrong range");
+ throw new IOException(Messages.HttpResponse_wrongRange);
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/IResponse.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/IResponse.java
new file mode 100644
index 0000000..f37b819
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/IResponse.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 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.update.internal.core.connection;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public interface IResponse {
+
+ /**
+ * Method getInputStream.
+ *
+ * @return InputStream
+ */
+ public InputStream getInputStream() throws IOException;
+
+ /**
+ * A special version of 'getInputStream' that can be canceled.
+ * A monitor thread checks the state of the monitor
+ * and disconnects the connection if 'isCanceled()' is detected.
+ *
+ * @param monitor
+ * the progress monitor
+ * @return InputStream an opened stream or null if failed.
+ * @throws IOException
+ * if there are problems
+ * @throws CoreException
+ * if no more connection threads are available
+ */
+ public InputStream getInputStream(IProgressMonitor monitor)
+ throws IOException, CoreException, TooManyOpenConnectionsException;
+
+ /**
+ * Method getContentLength.
+ *
+ * @return long
+ */
+ public long getContentLength();
+
+ /**
+ * Method getStatusCode.
+ *
+ * @return int
+ */
+ public int getStatusCode();
+
+ /**
+ * Method getStatusMessage.
+ *
+ * @return String
+ */
+ public String getStatusMessage();
+
+ /**
+ * Returns the timestamp of last modification to the resource
+ *
+ * @return
+ */
+ public long getLastModified();
+
+ /**
+ * Close the connection if open.
+ */
+ public void close();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/OtherResponse.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/OtherResponse.java
new file mode 100644
index 0000000..fe9d82e
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/OtherResponse.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.core.connection;
+
+import org.eclipse.update.internal.core.UpdateCore;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public class OtherResponse extends AbstractResponse {
+
+ protected URL url;
+ protected InputStream in;
+ protected long lastModified;
+
+ protected OtherResponse(URL url) {
+ this.url = url;
+ }
+
+ public InputStream getInputStream() throws IOException {
+ if (in == null && url != null) {
+ if (connection == null)
+ connection = url.openConnection();
+ in = connection.getInputStream();
+ this.lastModified = connection.getLastModified();
+ }
+ return in;
+ }
+
+ public void close() {
+ if( null != in ) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ }
+ in = null;
+ }
+ }
+
+ /**
+ * @see IResponse#getInputStream(IProgressMonitor)
+ */
+ public InputStream getInputStream(IProgressMonitor monitor)
+ throws IOException, CoreException {
+ if (in == null && url != null) {
+ if (connection == null)
+ connection = url.openConnection();
+
+ if (monitor != null) {
+ this.in =
+ openStreamWithCancel(connection, monitor);
+ } else {
+ this.in = connection.getInputStream();
+ }
+ if (in != null) {
+ this.lastModified = connection.getLastModified();
+ }
+ }
+ return in;
+ }
+
+ public long getContentLength() {
+ if (connection != null)
+ return connection.getContentLength();
+ return 0;
+ }
+
+ public int getStatusCode() {
+ return UpdateCore.HTTP_OK;
+ }
+
+ public String getStatusMessage() {
+ return ""; //$NON-NLS-1$
+ }
+
+ public long getLastModified() {
+ if (lastModified == 0 && connection != null) {
+ lastModified = connection.getLastModified();
+ }
+ return lastModified;
+ }
+
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/TooManyOpenConnectionsException.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/TooManyOpenConnectionsException.java
new file mode 100644
index 0000000..a8f846e
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/connection/TooManyOpenConnectionsException.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.core.connection;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+
+
+public class TooManyOpenConnectionsException extends CoreException {
+
+ private static final long serialVersionUID = 1L;
+
+ public TooManyOpenConnectionsException(IStatus status) {
+ super(status);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/messages.properties b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/messages.properties
new file mode 100644
index 0000000..c8020cb
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/messages.properties
@@ -0,0 +1,279 @@
+###############################################################################
+# Copyright (c) 2000, 2009 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
+###############################################################################
+# Install Update Core Properties File
+#
+
+ProductProvider=Update Manager
+BaseSiteFactory_CannotRetriveParentDirectory=Unable to retrieve parent directory for URL \"{0}\".
+ContentReference_UnableToCreateInputStream= Unable to create an input stream for the reference \"{0}\".
+ContentReference_UnableToReturnReferenceAsFile= Unable to return reference \"{0}\" as File.
+ContentReference_UnableToReturnReferenceAsURL= Unable to return reference \"{0}\" as URL.
+ContentReference_HttpNok= Server returned HTTP response code: \"{0} {1}\" for URL: {2}.
+ContentReference_FileDoesNotExist=The file \"{0}\" does not exist on the file system.
+Feature_SiteAlreadySet= Internal Error: Site already set for the feature \"{0}\".
+Feature_TaskInstallFeatureFiles= Installing feature files:
+Feature_TaskInstallPluginFiles= Installing plug-in \"{0}\" files:
+Feature_NoContentProvider= Internal Error. The feature \"{0}\" does not have a content provider.
+Feature_NoFeatureContentConsumer= Internal Error. The Feature \"{0}\" does not have a content consumer.
+Feature_NoURL= Unknown URL.
+Feature_FeatureVersionToString= Feature: \"{0}\" Version: \"{1}\".
+Feature_InstallationCancelled= Installation has been cancelled by the User.
+Feature_UnableToInitializeFeatureReference= Unable to initialize feature reference for versioned identifier \"{0}\".
+FeatureContentProvider_Downloading= Downloading:
+FeatureContentProvider_UnableToRetrieve= Unable to retrieve remote reference \"{0}\".
+FeatureContentProvider_UnableToCreate= Unable to create local file \"{0}\".
+FeatureContentProvider_ExceptionDownloading = An exception occurred while downloading feature from \"{0}\".
+InstallHandler_unableToCreateHandler = Unable to create custom install handler for feature \"{0}\".
+InstallHandler_notFound = Custom install handler required by feature \"{0}\" was not found.
+InstallHandler_invalidHandler = Feature \"{0}\" contains invalid custom install handler.
+InstallHandler_callException = Error reported by custom install handler for feature \"{0}\".
+InstallHandler_error = Unable to complete action for feature \"{0}\" due to errors.
+InstallCommand_site=site {0}
+InstallMonitor_DownloadSize = ({0}K bytes)
+InstallMonitor_DownloadSizeLong = ({0}K of {1}K bytes)
+JarContentReference_Unpacking= Unpacking:
+Site_CannotFindCategory= Unable to find category: \"{0}\" in Site: \"{1}\".
+Site_NoCategories= The Site does not contain any categories.
+Site_NoContentProvider= Internal Error. Content Provider not set for Site: \"{0}\".
+VersionedIdentifier_IdOrVersionNull= Internal Error. Unable to create an Identifier. The unique identifier or the version is null or empty: unique identifier=\"{0}\" version=\"{1}\".
+SiteFile_CannotRemovePlugin= Unable to remove plug-in: \"{0}\" from Site: \"{1}\".
+SiteFile_CannotRemoveFeature= Unable to remove feature: \"{0}\" from Site: \"{1}\".
+SiteFile_UnableToCreateURL= Unable to create URL for location \"{0}\".
+SiteFile_Removing= Removing:
+SiteFileFactory_UnableToCreateURL= Internal Error. Unable to create URL from \"{0}\".
+SiteFileFactory_UnableToAccessSite= Unable to access site
+SiteFileFactory_DirectoryDoesNotExist=The directory \"{0}\" does not exist on the file system.
+DefaultFeatureParser_location= Feature location: {0}
+DefaultFeatureParser_NoFeatureTag= Error parsing feature stream. Unable to find root element \"feature\" in the stream.
+DefaultFeatureParser_WrongParsingStack= Internal Error parsing feature stream. Unexpected Parsing Stack: \"{0}\"
+DefaultFeatureParser_UnknownElement= Error parsing feature stream. Unknown element \"{0}\" in parsing state \"{1}\". Check the validity of the XML file.
+DefaultFeatureParser_TooManyURLtag= Error parsing feature stream. There is more than one \"URL\" element in the XML stream. There should be only one.
+DefaultFeatureParser_UnknownStartState= Internal Error parsing feature stream. Unknown start state \"{0}\".
+DefaultFeatureParser_IdOrVersionInvalid= Error parsing feature stream. The unique identifier or the version is null or empty for the State: \"{2}\": unique identifier=\"{0}\" version=\"{1}\".
+DefaultFeatureParser_MissingId= Error parsing feature stream. The \"id\" tag of the element \"{0}\" is null or empty. Value is required.
+DefaultFeatureParser_ParsingStackBackToInitialState= Internal Error parsing feature stream. Parsing stack back to Initial State.
+DefaultFeatureParser_ElementAlreadySet= Error parsing feature stream. Element: \"{0}\" already set for the feature.
+DefaultFeatureParser_StateIncludeWrongElement= Error parsing feature stream. State: \"{0}\" should not include Element \"{1}\".
+DefaultFeatureParser_RequireStateWithoutImportElement=Error parsing feature stream. State: \"require\" must include at least an \"import\" element.
+DefaultFeatureParser_MissingPatchVersion=Error parsing feature stream. Attribute "version" of the element "import" must be set when "patch" is set to "true".
+DefaultFeatureParser_wrongMatchForPatch=Error parsing feature stream. When attribute "patch" of the element "import" is set to "true", the only valid value for the "match" attribute is "perfect".
+DefaultFeatureParser_patchWithPlugin=Error parsing feature stream. Attribute "patch" can only be used for features.
+DefaultFeatureParser_MultiplePatchImports=Error parsing feature stream. State: "require" must not contain more than one "import" element with the attribute "patch" set to "true".
+DefaultFeatureParser_UnknownEndState= Internal Error parsing feature stream. Unknown end state \"{0}\".
+DefaultFeatureParser_ErrorParsing= Error Parsing feature stream. Error: \"{0}\"
+DefaultFeatureParser_ErrorlineColumnMessage= Error Parsing feature stream. Element \"{0}\" line: \"{1}\" column:\"{2}\". Error: \"{3}\".
+DefaultFeatureParser_ErrorParsingFeature= Error Parsing feature stream.
+DefaultFeatureParser_UnknownState= Unknown State \"{0}\".
+DefaultFeatureParser_NoLicenseText= Error parsing feature stream. State: \"license\" must include some text.
+DefaultFeatureParser_PluginAndFeatureId=One Import statement is incorrect: Both feature and plug-in ID are either null or specified.
+SiteContentProvider_ErrorCreatingURLForArchiveID= Internal Error. Unable to create URL for Archive Identifier \"{0}\" on Site \"{1}\".
+DefaultSiteParser_NoSiteTag= Error parsing site stream. Unable to find root element \"site\" in the stream.
+DefaultSiteParser_WrongParsingStack= Internal Error parsing site stream. Unexpected Parsing Stack: \"{0}\"
+DefaultSiteParser_UnknownElement= Error parsing site stream. Unknown element \"{0}\" in parsing state \"{1}\". Check the validity of the XML file.
+DefaultSiteParser_UnknownStartState= Internal Error parsing site stream. Unknown start state \"{0}\".
+DefaultSiteParser_Missing= Error parsing site stream. The \"{0}\" tag of the element \"{1}\" is null or empty. Value is required.
+DefaultSiteParser_ParsingStackBackToInitialState= Internal Error parsing site stream. Parsing stack back to Initial State.
+DefaultSiteParser_ElementAlreadySet= Error parsing site stream. Element: \"{0}\" already set for the Site.
+DefaultSiteParser_UnknownEndState= Internal Error parsing site stream. Unknown end state \"{0}\".
+DefaultSiteParser_ErrorParsing= Error Parsing site stream. Error: \"{0}\"
+DefaultSiteParser_ErrorlineColumnMessage= Error Parsing site stream. Element \"{0}\" line: \"{1}\" column:\"{2}\". Error: \"{3}\".
+DefaultSiteParser_ErrorParsingSite= Error Parsing site stream.
+DefaultSiteParser_UnknownState= Unknown State \"{0}\".
+DefaultSiteParser_InvalidXMLStream= The XML stream is not a valid default \"site.xml\" file. The root tag is not site.
+ModelObject_ModelReadOnly= Internal Error. The Model Object is read-only.
+SiteModelObject_ErrorParsingSiteStream= Error parsing site stream.
+SiteModelObject_ErrorAccessingSiteStream= Error accessing site stream.
+InstallConfiguration_ErrorDuringFileAccess= Error accessing file: \"{0}\".
+InstallConfigurationParser_FeatureReferenceNoURL= Error Parsing Stream. A feature reference element does not have a URL tag. Value is required.
+FeatureExecutableContentProvider_FileDoesNotExist= The file \"{0}\" does not exist.
+FeatureExecutableContentProvider_InvalidDirectory= The path \"{0}\" is not a valid directory.
+FeatureExecutableContentProvider_UnableToCreateURLFor=Unable to create a URL for \"{0}\".
+FeatureExecutableContentProvider_UnableToRetrieveNonPluginEntry=Error retrieving the non-plug-in entry: \"{0}\".
+FeatureExecutableContentProvider_UnableToRetrieveFeatureEntry=Error retrieving feature entry content reference: \"{0}\".
+FeatureExecutableContentProvider_UnableToRetrievePluginEntry =Error retrieving the plug-in entry: \"{0}\".
+ConfiguredSite_NonInstallableSite= You cannot install in the site \"{0}\". It is considered non updateable.
+ConfiguredSite_NullFeatureToInstall= Internal Error. The feature to be installed is null.
+ConfiguredSite_NonUninstallableSite= You cannot uninstall from the site \"{0}\". It is considered non updateable.
+ConfiguredSite_NoSite= No Site
+ConfiguredSite_CannotFindFeatureToUnconfigure= Internal Error. Unable to disable feature \"{0}\" on site \"{1}\". Cannot find feature.
+ConfiguredSite_CannotFindFeatureToConfigure= Internal Error. Unable to enable feature \"{0}\". Cannot find feature.
+ConfiguredSite_CannotFindPluginEntry= Unable to retrieve Plug-in Entry \"{0}\" on site \"{1}\". Cannot find plug-in entry. Do you want to Continue ?
+ConfiguredSite_MissingPluginsBrokenFeature= Plug-in \"{0}\" version \"{1}\" referenced by this feature is missing.
+ConfiguredSite_UnableToRemoveConfiguredFeature= Unable to remove a enabled feature: \"{0}\" You must disable the feature first.
+ConfiguredSite_UnableToFindFeature= Unable to Find the feature \"{0}\" on this site.
+ConfiguredSite_SiteURLNull=The Site URL is null.
+ConfiguredSite_NonLocalSite=The Site is not on the local file system. Cannot validate.
+ConfiguredSite_NotSameProductId=The site cannot be modified by this product. It is already associated with product: \"{0}\".
+ConfiguredSite_ContainedInAnotherSite=This site is contained in another site: \"{0}\".
+ConfiguredSite_ReadOnlySite=The site is marked as read only.
+ConfiguredSite_UnableResolveURL= Internal Error. Unable to resolve URL \"{0}\".
+ConfiguredSite_UnableToAccessSite= Internal Error. Unable to access platform site \"{0}\".
+FeatureFactory_CreatingError= Error creating feature \"{0}\".
+FeatureModelFactory_ErrorAccesingFeatureStream= Error accessing feature stream.
+FeatureExecutableFactory_NullURL= Error creating feature. The URL used to create the feature is null.
+FeatureExecutableFactory_CannotCreateURL= Error creating feature. Unable to create URL for \"{0}\".
+FeaturePackagedContentProvider_NoManifestFile= Unable to retrieve \"{0}\" in feature located at \"{1}\".
+FeaturePackagedContentProvider_InvalidDirectory= The directory \"{0}\" is not a valid directory.
+FeaturePackagedContentProvider_ErrorRetrieving= Error retrieving \"{0}\".
+FeatureReference_UnableToResolveURL= Internal Error: Unable to resolve model using URL: \"{0}\".
+FeatureTypeFactory_UnableToFindFeatureFactory= Unable to find a feature factory for the extension id \"{0}\".
+InstallConfiguration_UnableToCreateURL= Unable to create URL from \"{0}\".
+InstallConfiguration_UnableToCast= Internal Error. The Configuration Site object is not a subclass of ConfiguredSiteModel
+InstallConfiguration_UnableToSavePlatformConfiguration=Unable to save platform configuration in \"{0}\".
+InstallConfiguration_AlreadyNativelyLinked=The site is already linked.
+InstallConfiguration_AlreadyProductSite=The location is already a product site.
+InstallConfiguration_unableToFindSite=Unable to find site {0} in platform configuration {1}.
+InternalSiteManager_UnableToCreateSiteWithType= Extension Error. The Site Factory of type \"{0}\" cannot access the Site \"{1}\".
+InternalSiteManager_UnableToAccessURL= Unable to access \"{0}\".
+InternalSiteManager_UnableToCreateURL= Unable to create URL from \"{0}\".
+InternalSiteManager_FailedRetryAccessingSite= Failed retry accessing site using default installed format instead of default packaged format.
+InternalSiteManager_ConnectingToSite = Connecting To Site...
+GlobalConsumer_ErrorCreatingFile= Unable to create file \"{0}\".
+SiteFileContentConsumer_UnableToCreateURL= Unable to create URL from \"{0}\".
+SiteFileContentConsumer_UnableToCreateURLForFile= Unable to create URL for the file \"{0}\".
+SiteFileContentConsumer_unableToDelete=Unable to delete {0}
+ContentConsumer_UnableToRename = Internal Error. Unable to rename \"{0}\" to \"{1}\".
+SiteFileFactory_UnableToObtainParentDirectory= Unable obtain the parent directory from the file \"{0}\".
+SiteFileFactory_FileDoesNotExist= Unable to access site \"{0}\". The directory does not exist.
+SiteFileFactory_UnableToCreateURLForFile= Unable to create URL from \"{0}\".
+SiteFileFactory_ErrorParsingFile= Unable to parse file \"{0}\".
+SiteFileFactory_ErrorAccessing= Unable to access file \"{0}\".
+SiteTypeFactory_UnableToFindSiteFactory= Unable to find a site factory for the extension id \"{0}\".
+UpdateManagerUtils_UnableToRemoveFile= Unable to remove \"{0}\" from the file system.
+UpdateManagerUtils_FileAlreadyExists= Unable to create \"{0}\" on the file system. File already exists.
+SiteLocal_UnableToCreateURLFor= Unable to create URL from \"{0}\".
+SiteLocal_UnableToDetermineFeatureStatusSiteNull=Unable to determine status of feature\"{0}\" The site is NULL.
+SiteLocal_TwoVersionSamePlugin1=Plug-in: \"{0}\" version: \"{1}\" referenced by this feature is not included at runtime. Runtime includes plug-in version \"{2}\".
+SiteLocal_TwoVersionSamePlugin2=Plug-in: \"{0}\" version: \"{1}\" referenced by this feature is not included at runtime. Runtime includes plug-in version \"{2}\" supplied by feature \"{3}\" version \"{4}\".
+SiteLocal_FeatureUnHappy=The feature is not configured properly.
+SiteLocal_FeatureHappy=The feature is configured properly.
+SiteLocal_FeatureAmbiguous=The feature may not be configured properly.
+SiteLocal_NestedFeatureUnHappy=Included feature \"{0}\" version \"{1}\" contains problems.
+SiteLocal_NestedFeatureUnavailable=Included feature \"{0}\" is missing.
+SiteLocal_NoPluginVersion=No plug-in: \"{0}\" included at runtime.
+SiteLocal_UnableToDetermineFeatureStatusConfiguredSiteNull=Unable to determine status of feature\"{0}\" The Configured Site is NULL.
+SiteLocal_FeatureDisable=The feature is disabled.
+SiteLocal_FeatureStatusUnknown=Unknown state.
+SiteLocal_NestedFeatureDisable=Included feature \"{0}\" version \"{1}\" is disabled.
+SiteURLFactory_UnableToCreateURL= Internal Error. Unable to create a URL from \"{0}\".
+SiteURLFactory_UnableToAccessSiteStream= Unable to access site: \"{0}\"
+JarVerifier_Verify= Verifying: \"{0}\"
+JarVerifier_UnableToFindEncryption= Unable to find algorithm to verify integrity of KeyStore \"{0}\".
+JarVerifier_UnableToLoadCertificate= Unable to load one or multiples certificates in the KeyStore \"{0}\".
+JarVerifier_UnableToFindProviderForKeystore= Unable to find provider for the KeyStore type \"{0}\".
+JarVerifier_KeyStoreNotLoaded= Internal Error. KeyStore not Initialized/Loaded.
+JarVerifier_UnableToAccessJar= Unable to access JAR file \"{0}\".
+JarVerifier_InvalidFile= The File \"{0}\" is not a valid JAR file. It does not contain a Manifest.
+JarVerifier_InvalidJar= The File \"{0}\" is not a valid JAR file.
+JarVerificationResult_ValidBetween= Valid between \"{0}\" and \"{1}\".
+JarVerificationResult_ExpiredCertificate= * EXPIRED CERTIFICATE *
+JarVerificationResult_CertificateNotYetValid= * CERTIFICATE NOT YET VALID *
+JarVerificationResult_CertificateValid= Valid certificate.
+JarVerificationService_UnsucessfulVerification=Verification of feature unsuccessful. Installation cancelled.
+JarVerificationService_CancelInstall=Installation cancelled.
+UpdateManagerUtils_UnableToLog=Unable to access error recovery log file: \"{0}\".
+ConnectionThreadManager_tooManyConnections = There are too many network connections still active. \
+If you are experiencing network problems, try again later. If the error persists, restart the \
+application.
+ConnectionThreadManager_unresponsiveURL = Still waiting for response: {0}
+IncludedFeatureReference_featureUninstalled= Feature {0} is uninstalled.
+
+# Properties moved mostly from the ui plugin
+
+ActivityConstraints_warning=The current configuration contains errors and this operation can have unpredictable results.
+ActivityConstraints_rootMessage = Requested operation cannot be performed because it would invalidate the current configuration. See details for more information.
+ActivityConstraints_rootMessageInitial = Current configuration contains errors that are not corrected by the requested operation and more errors would be introduced. See details for more information.
+ActivityConstraints_beforeMessage = ----- Current configuration problems -----
+ActivityConstraints_afterMessage = ----- Configuration problems after the operation -----
+ActivityConstraints_platform = Resulting configuration does not contain the platform.
+ActivityConstraints_primary = Resulting configuration does not contain the primary feature.
+ActivityConstaints_prereq_plugin = plug-in
+ActivityConstaints_prereq_feature = feature
+ActivityConstraints_prereq = requires {0} "{1}".
+ActivityConstraints_prereqPerfect = requires {0} "{1} ({2})".
+ActivityConstraints_prereqEquivalent = requires {0} "{1} ({2})", or equivalent.
+ActivityConstraints_prereqCompatible = requires {0} "{1} ({2})", or compatible.
+ActivityConstraints_prereqGreaterOrEqual = requires {0} "{1} ({2})", or later version.
+ActivityConstraints_os = operating system does not match current environment.
+ActivityConstraints_ws = windowing system does not match current environment.
+ActivityConstraints_arch = platform architecture does not match current environment.
+ActivityConstraints_cycle = definition contains a nested features cycle: {0}_{1}prereq
+ActivityConstraints_childMessage = {0} ({1}) {2}
+ActivityConstraints_optionalChild = Feature included in another feature cannot be enabled if the parent is disabled. Enable the parent first.
+ActivityConstraints_exclusive = must be processed separately from other features.
+ActivityConstraints_noLicense = does not have a valid license agreement.
+ActivityConstraints_readOnly = The site is not updateable: {0}.
+ActivityConstraints_platformModified = Platform configuration has been modified outside this program. A restart is recommended.
+DuplicateConflictsDialog_conflict = Version {0} in {1}
+OperationsManager_error_old= {0}: Error while updating the old feature version
+OperationsManager_installing=Initializing...
+OperationsManager_error_uninstall= {0} : Error while uninstalling feature
+Search_networkProblems=Network connection problems encountered during search.
+InstallConfiguration_location_exists = Site already exists.
+InstallLogParser_errors = Errors generated while parsing installation history file.
+SiteLocal_cloneConfig=Error clonning current configuration.
+
+UninstallCommand_featureNotInstalledByUM=Feature not installed by Update Manager: {0}
+
+UpdateManagerUtils_inputStreamEnded=InputStream ended after {0} bytes (expected {1} )
+UpdateSearchRequest_loadingPolicy=Loading update policy ...
+UpdateManagerUtils_copy=UpdateManagerUtils copy() at offset:
+UpdatePolicy_parsePolicy=Errors while parsing update policy
+UpdatePolicy_policyExpected=' is expected.
+UpdateSearchRequest_searching=Searching...
+UpdateSearchRequest_contacting=Contacting {0} ...
+UpdateSearchRequest_checking=Checking {0} ...
+UpdatePolicy_invalidURL=invalid URL -
+UpdatePolicy_nameNoNull= cannot be null.
+UpdatePolicy_UpdatePolicy=Update Policy:
+SiteFile_featureNotRemoved=Feature {0} was not removed
+SiteFile_pluginNotRemoved=Plugin {0} was not removed
+ErrorRecoveryLog_noFiletoRemove=Unable to find file to remove:
+UpdatesSearchCategory_errorSearchingForUpdates=Error while initializing the search for new updates
+Standalone_siteConfigured=Site is already configured:
+Standalone_noSite=Cannot find site:
+Standalone_noSite3=No site specified
+Standalone_noConfiguredSite=Cannot find configured site:
+Standalone_installing=Installing feature
+Standalone_notFoundOrNewer=Feature {0} cannot be found on {1} \nor a newer version is already installed.
+Standalone_duplicate=Duplicate conflicts
+Standalone_installed= Feature {0} has successfully been installed
+Standalone_cannotInstall=Cannot install feature
+Standalone_noFeatures1=There are no unconfigured features with id {0}
+Standalone_noFeatures2=Cannot find unconfigured feature {0} with version {1}
+Standalone_noFeatures3=There are no configured features with id {0}
+Standalone_noFeatures4=Cannot find configured feature {0} with version {1}
+Standalone_noConfigSiteForFeature=There are no configured sites for feature {0}
+Standalone_invalidCmd=Invalid command:
+Standalone_connection = Connection error
+Standalone_searching = Searching on:
+Standalone_cmdFailed = Command failed. Please check log file {0} for details.
+Standalone_cmdFailedNoLog = Command failed.
+Standalone_cmdCompleteWithErrors = Command completed with errors. Please check log file {0} for details.
+Standalone_cmdOK = Command completed successfully.
+Standalone_updating = Begin updating
+Standalone_noUpdate = Feature {0} cannot be updated.
+Standalone_updated= Feature {0} has successfully been updated.
+SiteFilePluginContentConsumer_unableToDelete=Unable to delete {0}
+SiteFilePackedPluginContentConsumer_unableToDelete=Unable to delete {0}
+
+JarProcessor_unpackNotFound = The unpack200 command cannot be found.
+JarProcessor_noPackUnpack = Pack, repack or sign cannot be specified with unpack.
+JarProcessor_packNotFound = The pack200 command cannot be found.
+SiteOptimizer_inputNotSpecified = No input file was specified;
+SiteOptimizer_inputFileNotFound = The input file \"{0}\" was not found.
+
+HttpResponse_rangeExpected = Server does not support ranges.
+HttpResponse_wrongRange = Server returned wrong range.
+DefaultSiteParser_mirrors = Error processing update site mirror.
+FeatureExecutableContentProvider_UnableToRetriveArchiveContentRef = Unable to retrieve archive content reference
+SiteCategory_other_label = Other
+SiteCategory_other_description = Features found under this category are either not categorized or their categories could not be found on server.
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/mirror/MirrorCommand.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/mirror/MirrorCommand.java
new file mode 100644
index 0000000..9b039c7
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/mirror/MirrorCommand.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.mirror;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.PluginVersionIdentifier;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.ISiteFeatureReference;
+import org.eclipse.update.core.JarContentReference;
+import org.eclipse.update.core.SiteFeatureReference;
+import org.eclipse.update.core.SiteFeatureReferenceModel;
+import org.eclipse.update.core.SiteManager;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.core.VersionedIdentifier;
+import org.eclipse.update.core.model.InvalidSiteTypeException;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.standalone.ScriptedCommand;
+import org.eclipse.update.standalone.StandaloneUpdateApplication;
+
+/**
+ * Mirrors a remote site locally.
+ */
+public class MirrorCommand extends ScriptedCommand {
+
+ private String featureId;
+ private String featureVersion;
+ private String fromSiteUrl;
+ private String toSiteDir;
+ private String mirrorURL;
+ private boolean ignoreNonPresentPlugins = false;
+ private MirrorSite mirrorSite;
+
+ public MirrorCommand(
+ String featureId,
+ String featureVersion,
+ String fromSiteUrl,
+ String toSiteDir,
+ String mirrorUrl,
+ String ignoreNonPresentPlugins) {
+ this.featureId = featureId;
+ this.featureVersion = featureVersion;
+ this.fromSiteUrl = fromSiteUrl;
+ this.toSiteDir = toSiteDir;
+ this.mirrorURL = mirrorUrl;
+ this.ignoreNonPresentPlugins = (ignoreNonPresentPlugins != null) && (ignoreNonPresentPlugins.equals("true")); //$NON-NLS-1$
+ }
+
+ /**
+ * true if success
+ */
+ public boolean run(IProgressMonitor monitor) {
+ if (!validateParameters()) {
+ return false;
+ }
+
+ try {
+ if (getMirrorSite() == null)
+ return false;
+
+ URL remoteSiteUrl = new URL(fromSiteUrl);
+ ISite remoteSite =
+ SiteManager.getSite(remoteSiteUrl, new NullProgressMonitor());
+
+ ISiteFeatureReference featureReferencesToMirror[] =
+ findFeaturesToMirror(remoteSite);
+ if (featureReferencesToMirror.length == 0) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(
+ Utilities.newCoreException(
+ "No matching features found on " + remoteSiteUrl + ".", //$NON-NLS-1$ //$NON-NLS-2$
+ null));
+ return false;
+ }
+
+ mirrorSite.mirrorAndExpose(
+ remoteSite,
+ featureReferencesToMirror,
+ null,
+ mirrorURL);
+ return true;
+ } catch (MalformedURLException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ return false;
+ } catch (CoreException ce) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(ce);
+ return false;
+ } finally {
+ JarContentReference.shutdown();
+ }
+ }
+ private boolean validateParameters() {
+ if (fromSiteUrl == null || fromSiteUrl.length() <= 0) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(
+ Utilities.newCoreException("from parameter is missing.", null)); //$NON-NLS-1$
+ return false;
+ }
+ try {
+ new URL(fromSiteUrl);
+ } catch (MalformedURLException mue) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(
+ Utilities.newCoreException("from must be a valid URL", null)); //$NON-NLS-1$
+ return false;
+ }
+ if (toSiteDir == null || toSiteDir.length() <= 0) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(
+ Utilities.newCoreException("to parameter is missing.", null)); //$NON-NLS-1$
+ return false;
+ }
+ return true;
+ }
+ private MirrorSite getMirrorSite()
+ throws MalformedURLException, CoreException {
+ // Create mirror site
+ if (mirrorSite == null) {
+ if (toSiteDir != null) {
+ MirrorSiteFactory factory = new MirrorSiteFactory();
+ System.out.print("Analyzing features already mirrored ..."); //$NON-NLS-1$
+ try {
+ mirrorSite =
+ (MirrorSite) factory.createSite(new File(toSiteDir));
+ mirrorSite.setIgnoreNonPresentPlugins(ignoreNonPresentPlugins);
+ } catch (InvalidSiteTypeException iste) {
+ }
+ System.out.println(" Done."); //$NON-NLS-1$
+ }
+ if (mirrorSite == null) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(
+ Utilities.newCoreException(
+ "Mirror site at " + toSiteDir + " cannot be accessed.", //$NON-NLS-1$ //$NON-NLS-2$
+ null));
+ return null;
+ }
+ }
+ return mirrorSite;
+
+ }
+ /**
+ * Returns subset of feature references on remote site
+ * as specified by optional featureId and featureVersion
+ * parameters
+ * @param remoteSite
+ * @return ISiteFeatureReference[]
+ * @throws CoreException
+ */
+ private ISiteFeatureReference[] findFeaturesToMirror(ISite remoteSite)
+ throws CoreException {
+ ISiteFeatureReference remoteSiteFeatureReferences[] =
+ remoteSite.getRawFeatureReferences();
+ SiteFeatureReferenceModel existingFeatureModels[] =
+ mirrorSite.getFeatureReferenceModels();
+ Collection featureReferencesToMirror = new ArrayList();
+
+ PluginVersionIdentifier featureVersionIdentifier = null;
+
+ if (featureId == null) {
+ System.out.println(
+ "Parameter feature not specified. All features on the remote site will be mirrored."); //$NON-NLS-1$
+ }
+ if (featureVersion == null) {
+ System.out.println(
+ "Parameter version not specified. All versions of features on the remote site will be mirrored."); //$NON-NLS-1$
+ } else {
+ featureVersionIdentifier =
+ new PluginVersionIdentifier(featureVersion);
+ }
+ for (int i = 0; i < remoteSiteFeatureReferences.length; i++) {
+ VersionedIdentifier remoteFeatureVersionedIdentifier =
+ remoteSiteFeatureReferences[i].getVersionedIdentifier();
+
+ if (featureId != null
+ && !featureId.equals(
+ remoteFeatureVersionedIdentifier.getIdentifier())) {
+ // id does not match
+ continue;
+ }
+ if (featureVersionIdentifier != null
+ && !featureVersionIdentifier.isPerfect(
+ remoteFeatureVersionedIdentifier.getVersion())) {
+ // version does not match
+ continue;
+ }
+
+ for (int e = 0; e < existingFeatureModels.length; e++) {
+ if (existingFeatureModels[e]
+ .getVersionedIdentifier()
+ .equals(remoteFeatureVersionedIdentifier)) {
+ System.out.println(
+ "Feature " //$NON-NLS-1$
+ + remoteFeatureVersionedIdentifier
+ + " already mirrored and exposed."); //$NON-NLS-1$
+ // feature already mirrored and exposed in site.xml
+ continue;
+ }
+ }
+
+ // Check feature type
+ String type =
+ ((SiteFeatureReference) remoteSiteFeatureReferences[i])
+ .getType();
+ if (type != null
+ && !ISite.DEFAULT_PACKAGED_FEATURE_TYPE.equals(type)) {
+ // unsupported
+ throw Utilities.newCoreException(
+ "Feature " //$NON-NLS-1$
+ + remoteFeatureVersionedIdentifier
+ + " is of type " //$NON-NLS-1$
+ + type
+ + ". Only features of type " //$NON-NLS-1$
+ + ISite.DEFAULT_PACKAGED_FEATURE_TYPE
+ + " are supported.", //$NON-NLS-1$
+ null);
+ }
+
+ featureReferencesToMirror.add(remoteSiteFeatureReferences[i]);
+ System.out.println(
+ "Feature " //$NON-NLS-1$
+ + remoteSiteFeatureReferences[i].getVersionedIdentifier()
+ + " will be mirrored."); //$NON-NLS-1$
+ }
+ return (ISiteFeatureReference[]) featureReferencesToMirror.toArray(
+ new ISiteFeatureReference[featureReferencesToMirror.size()]);
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/mirror/MirrorSite.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/mirror/MirrorSite.java
new file mode 100644
index 0000000..7c40fe3
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/mirror/MirrorSite.java
@@ -0,0 +1,822 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.mirror;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.update.core.ContentReference;
+import org.eclipse.update.core.ICategory;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IFeatureContentProvider;
+import org.eclipse.update.core.IFeatureReference;
+import org.eclipse.update.core.INonPluginEntry;
+import org.eclipse.update.core.IPluginEntry;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.ISiteFeatureReference;
+import org.eclipse.update.core.IURLEntry;
+import org.eclipse.update.core.IVerificationListener;
+import org.eclipse.update.core.Site;
+import org.eclipse.update.core.SiteFeatureReferenceModel;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.core.VersionedIdentifier;
+import org.eclipse.update.core.model.CategoryModel;
+import org.eclipse.update.core.model.SiteModelFactory;
+import org.eclipse.update.core.model.URLEntryModel;
+import org.eclipse.update.internal.core.CoreExceptionWithRootCause;
+import org.eclipse.update.internal.core.FatalIOException;
+import org.eclipse.update.internal.core.FeaturePackagedContentProvider;
+import org.eclipse.update.internal.core.ISiteContentConsumer;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+import org.eclipse.update.standalone.StandaloneUpdateApplication;
+
+/**
+ * Local mirror site. Read/Write
+ */
+public class MirrorSite extends Site {
+ private final static String INDENT = " "; //$NON-NLS-1$
+ private SiteModelFactory factory;
+ /**
+ * plugin entries
+ */
+ private Collection downloadedPluginEntries = new ArrayList();
+ private Collection downloadedFeatureReferenceModels = new ArrayList();
+ private boolean ignoreNonPresentPlugins;
+ public MirrorSite(SiteModelFactory factory) {
+ this.factory = factory;
+ }
+
+ /**
+ * Mirrors the specified features and listed optional features on this site.
+ * @see ISite#install(IFeature, IVerificationListener, IProgressMonitor)
+ * @param mirrorSiteUrl external URL of the mirror site or null;
+ * if parameter is provided policy fragment will be generated
+ * @exception CoreException
+ */
+ public void mirrorAndExpose(
+ ISite remoteSite,
+ ISiteFeatureReference[] sourceFeatureRefs,
+ IFeatureReference[] optionalfeatures,
+ String mirrorSiteUrl)
+ throws CoreException {
+
+ mirrorAndExposeFeatures(
+ remoteSite,
+ sourceFeatureRefs,
+ optionalfeatures);
+
+ System.out.println(
+ "Installing features finished. Updating categories ..."); //$NON-NLS-1$
+ updateCategories(remoteSite);
+ System.out.println(
+ "Updating categories finished. Updating site description ..."); //$NON-NLS-1$
+ updateDescription(remoteSite);
+ System.out.println(
+ "Updating site description finished. Saving site.xml ..."); //$NON-NLS-1$
+ save();
+ if (mirrorSiteUrl != null) {
+ generateUpdatePolicy(mirrorSiteUrl);
+ }
+ }
+ private void mirrorAndExposeFeatures(
+ ISite remoteSite,
+ ISiteFeatureReference[] sourceFeatureRefs,
+ IFeatureReference[] optionalfeatures)
+ throws CoreException {
+
+ // Features that failed will be retried once again
+ Collection failedFeatures = new ArrayList();
+ for (int i = 0; i < sourceFeatureRefs.length; i++) {
+ try {
+ IFeature sourceFeature =
+ sourceFeatureRefs[i].getFeature(new NullProgressMonitor());
+ SiteFeatureReferenceModel featureRef =
+ mirrorFeature(
+ remoteSite,
+ sourceFeature,
+ optionalfeatures,
+ 1);
+ // Set categories of the new feature
+ ICategory remoteCategories[] =
+ sourceFeatureRefs[i].getCategories();
+ for (int j = 0; j < remoteCategories.length; j++) {
+ featureRef.addCategoryName(remoteCategories[j].getName());
+ }
+
+ addFeatureReferenceModel(remoteSite, featureRef);
+ } catch (CoreException ce) {
+ failedFeatures.add(sourceFeatureRefs[i]);
+ }
+ }
+
+ // do we need to retry?
+ if (failedFeatures.size() > 0) {
+ sourceFeatureRefs =
+ (ISiteFeatureReference[]) failedFeatures.toArray(
+ new ISiteFeatureReference[failedFeatures.size()]);
+ } else {
+ return;
+ }
+
+ for (int i = 0; i < sourceFeatureRefs.length; i++) {
+ IFeature sourceFeature =
+ sourceFeatureRefs[i].getFeature(new NullProgressMonitor());
+ SiteFeatureReferenceModel featureRef =
+ mirrorFeature(remoteSite, sourceFeature, optionalfeatures, 1);
+ // Set categories of the new feature
+ ICategory remoteCategories[] = sourceFeatureRefs[i].getCategories();
+ for (int j = 0; j < remoteCategories.length; j++) {
+ featureRef.addCategoryName(remoteCategories[j].getName());
+ }
+
+ addFeatureReferenceModel(remoteSite, featureRef);
+ }
+ }
+
+ /**
+ * Install the specified feature and listed optional features on this site.
+ * @see ISite#install(IFeature, IVerificationListener, IProgressMonitor)
+ * @exception CoreException
+ */
+ private SiteFeatureReferenceModel mirrorFeature(
+ ISite remoteSite,
+ IFeature sourceFeature,
+ IFeatureReference[] optionalfeatures,
+ int indent)
+ throws CoreException {
+ String tab = ""; //$NON-NLS-1$
+ for (int i = 0; i < indent; i++)
+ tab += " "; //$NON-NLS-1$
+ System.out.println(
+ tab
+ + "Mirroring feature " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " ..."); //$NON-NLS-1$
+ SiteFeatureReferenceModel existingFeatures[] =
+ getDownloadedFeatureReferenceModels();
+ for (int e = 0; e < existingFeatures.length; e++) {
+ if (existingFeatures[e]
+ .getVersionedIdentifier()
+ .equals(sourceFeature.getVersionedIdentifier())) {
+ System.out.println(
+ tab
+ + "Feature " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " already exists. Skipping downloading."); //$NON-NLS-1$
+ return existingFeatures[e];
+ }
+ }
+
+ final IFeatureContentProvider provider =
+ sourceFeature.getFeatureContentProvider();
+
+ // TODO: passing command options could be made more general in future, so this
+ // cast is not needed.
+ if (provider instanceof FeaturePackagedContentProvider) {
+ ((FeaturePackagedContentProvider) provider).setContinueOnError(ignoreNonPresentPlugins);
+ }
+
+ System.out.println(
+ tab
+ + "Getting plugin entries for " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " ..."); //$NON-NLS-1$
+ final IPluginEntry[] sourceFeaturePluginEntries =
+ sourceFeature.getRawPluginEntries();
+
+ // determine list of plugins to install
+ // find the intersection between the plugin entries already contained
+ // on the target site, and plugin entries packaged in source feature
+
+ IPluginEntry[] pluginsToInstall =
+ UpdateManagerUtils.diff(
+ sourceFeaturePluginEntries,
+ getDownloadedPluginEntries());
+
+ System.out.println(
+ tab
+ + "Getting non plugin entries for " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " ..."); //$NON-NLS-1$
+ final INonPluginEntry[] nonPluginsToInstall =
+ sourceFeature.getRawNonPluginEntries();
+
+ System.out.println(
+ tab
+ + "Getting included features for " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " ..."); //$NON-NLS-1$
+ IFeatureReference[] children =
+ sourceFeature.getRawIncludedFeatureReferences();
+ if (optionalfeatures != null) {
+ children =
+ UpdateManagerUtils.optionalChildrenToInstall(
+ children,
+ optionalfeatures);
+ }
+
+ System.out.println(
+ tab
+ + "Downloading feature archives for " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " ..."); //$NON-NLS-1$
+ // download feature archives
+ provider.getFeatureEntryArchiveReferences(null);
+
+ System.out.println(
+ tab
+ + "Downloading plug-in archives for " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " ..."); //$NON-NLS-1$
+ // download plugin archives
+ for (int i = 0; i < pluginsToInstall.length; i++) {
+ try {
+ provider.getPluginEntryArchiveReferences(pluginsToInstall[i], null);
+ } catch (CoreException ce) {
+ if ( ignoreNonPresentPlugins &&
+ (ce instanceof CoreExceptionWithRootCause) &&
+ (((CoreExceptionWithRootCause)ce).getRootException() != null) &&
+ (((CoreExceptionWithRootCause)ce).getRootException() instanceof FatalIOException) ) {
+ System.out.println("Could not mirror plug-in " + pluginsToInstall[i].getVersionedIdentifier().toString() + ". It does not exist on the given site"); //$NON-NLS-1$//$NON-NLS-2$
+ } else {
+ throw ce;
+ }
+ }
+ }
+
+ System.out.println(
+ tab
+ + "Downloading non plug-in archives for " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " ..."); //$NON-NLS-1$
+ // download non-plugin archives
+ for (int i = 0; i < nonPluginsToInstall.length; i++) {
+ provider.getNonPluginEntryArchiveReferences(
+ nonPluginsToInstall[i],
+ null);
+ }
+
+ System.out.println(
+ tab
+ + "Installing child features for " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " ..."); //$NON-NLS-1$
+ // install child features first
+ for (int i = 0; i < children.length; i++) {
+ IFeature childFeature = children[i].getFeature(null);
+ mirrorFeature(
+ remoteSite,
+ childFeature,
+ optionalfeatures,
+ indent + 1);
+ }
+
+ System.out.println(
+ tab
+ + "Storing plug-in archives for " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " ..."); //$NON-NLS-1$
+ // store plugins' archives
+ for (int i = 0; i < pluginsToInstall.length; i++) {
+ try {
+ ContentReference[] references = provider.getPluginEntryArchiveReferences( pluginsToInstall[i], null);
+ storePluginArchive(references[0]);
+ addDownloadedPluginEntry(pluginsToInstall[i]);
+ } catch (CoreException ce) {
+ if ( ignoreNonPresentPlugins &&
+ (ce instanceof CoreExceptionWithRootCause) &&
+ (((CoreExceptionWithRootCause)ce).getRootException() != null) &&
+ (((CoreExceptionWithRootCause)ce).getRootException() instanceof FatalIOException) ) {
+ System.out.println("Could not write plug-in " + pluginsToInstall[i].getVersionedIdentifier().toString() + ". It does not exist on the given site"); //$NON-NLS-1$ //$NON-NLS-2$
+ } else {
+ //System.out.println("ignoreNonPresentPlugins:"+ignoreNonPresentPlugins); //$NON-NLS-1$
+ throw ce;
+ }
+ }
+ }
+
+ System.out.println(
+ tab
+ + "Storing non plug-in archives for " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " ..."); //$NON-NLS-1$
+ // store non plugins' archives
+ for (int i = 0; i < nonPluginsToInstall.length; i++) {
+ ContentReference[] references =
+ provider.getNonPluginEntryArchiveReferences(
+ nonPluginsToInstall[i],
+ null);
+ for (int r = 0; r < references.length; r++) {
+ storeNonPluginArchive(
+ sourceFeature.getVersionedIdentifier(),
+ references[r]);
+ }
+ }
+
+ System.out.println(
+ tab
+ + "Storing feature archives for " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " ..."); //$NON-NLS-1$
+ // store feature archive
+ ContentReference[] references =
+ provider.getFeatureEntryArchiveReferences(null);
+ storeFeatureArchive(references[0]);
+
+ System.out.println(
+ tab
+ + "Adding feature " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " to model ..."); //$NON-NLS-1$
+
+ // add feature model to site model
+ SiteFeatureReferenceModel featureRef =
+ factory.createFeatureReferenceModel();
+ featureRef.setSiteModel(this);
+ //featureRef.setURLString(featureURL.toExternalForm());
+ featureRef.setType(ISite.DEFAULT_PACKAGED_FEATURE_TYPE);
+ featureRef.setFeatureIdentifier(
+ sourceFeature.getVersionedIdentifier().getIdentifier());
+ featureRef.setFeatureVersion(
+ sourceFeature.getVersionedIdentifier().getVersion().toString());
+ addDownloadedFeatureReferenceModel(featureRef);
+
+ System.out.println(
+ tab
+ + "Mirroring feature " //$NON-NLS-1$
+ + sourceFeature.getVersionedIdentifier()
+ + " finished."); //$NON-NLS-1$
+ return featureRef;
+
+ }
+ /**
+ * Adds a feature reference model to this site,
+ * and exposes in site.xml if remote site exposes given feature.
+ */
+ public void addFeatureReferenceModel(
+ ISite remoteSite,
+ SiteFeatureReferenceModel featureReference) {
+ // check if remote site exposes this feature
+ ISiteFeatureReference remoteFeatures[] =
+ remoteSite.getRawFeatureReferences();
+ for (int i = 0; i < remoteFeatures.length; i++) {
+ ISiteFeatureReference remoteFeatureRef = remoteFeatures[i];
+ try {
+ if (remoteFeatureRef
+ .getVersionedIdentifier()
+ .equals(featureReference.getVersionedIdentifier())) {
+ addFeatureReferenceModel(featureReference);
+ }
+ } catch (CoreException ce) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(ce);
+ }
+ }
+ save();
+ System.out.println(
+ "Feature " //$NON-NLS-1$
+ + featureReference.getVersionedIdentifier()
+ + " added to site.xml."); //$NON-NLS-1$
+ }
+ /**
+ * Adds feature model to site model, removing old feature
+ */
+ public void addFeatureReferenceModel(SiteFeatureReferenceModel featureReference) {
+ SiteFeatureReferenceModel[] existingModels =
+ getFeatureReferenceModels();
+ for (int j = 0; j < existingModels.length; j++) {
+ if (existingModels[j]
+ .getVersionedIdentifier()
+ .equals(featureReference.getVersionedIdentifier())) {
+ super.removeFeatureReferenceModel(existingModels[j]);
+ }
+ }
+ super.addFeatureReferenceModel(featureReference);
+ }
+
+ /**
+ * @see ISiteContentConsumer#store(ContentReference, IProgressMonitor)
+ */
+ private void storeFeatureArchive(ContentReference contentReference)
+ throws CoreException {
+ InputStream inStream = null;
+ String featurePath = null;
+
+ try {
+ URL newURL =
+ new URL(
+ this.getURL(),
+ Site.DEFAULT_INSTALLED_FEATURE_PATH
+ + contentReference.getIdentifier()
+ + ".jar"); //$NON-NLS-1$
+ featurePath = newURL.getFile();
+ inStream = contentReference.getInputStream();
+ UpdateManagerUtils.copyToLocal(inStream, featurePath, null);
+ } catch (IOException e) {
+ throw Utilities.newCoreException(
+ "Error occurred while creating "+ featurePath+" file.", //$NON-NLS-1$ //$NON-NLS-2$
+ e);
+ } finally {
+ if (inStream != null) {
+ try {
+ inStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ }
+ /**
+ * @see ISiteContentConsumer#store(ContentReference, IProgressMonitor)
+ */
+ private void storePluginArchive(ContentReference contentReference)
+ throws CoreException {
+
+ InputStream inStream = null;
+ String pluginPath = null;
+ try {
+ URL newURL = new URL(getURL(), contentReference.getIdentifier());
+ pluginPath = newURL.getFile();
+ inStream = contentReference.getInputStream();
+ // added null check here, since contentReference can, in theory, return null for input stream.
+ if (inStream != null) {
+ UpdateManagerUtils.copyToLocal(inStream, pluginPath, null);
+ }
+ } catch (IOException e) {
+ throw Utilities.newCoreException(
+ "Error occurred while creating "+ pluginPath+" file.", //$NON-NLS-1$ //$NON-NLS-2$
+ e);
+ } finally {
+ if (inStream != null) {
+ try {
+ inStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ private void storeNonPluginArchive(
+ VersionedIdentifier featureVersionedIdentifier,
+ ContentReference contentReference)
+ throws CoreException {
+
+ InputStream inStream = null;
+ File nonPluginArchivePath = null;
+ try {
+ URL newDirURL =
+ new URL(
+ getURL(),
+ Site.DEFAULT_INSTALLED_FEATURE_PATH
+ + "/" //$NON-NLS-1$
+ + featureVersionedIdentifier);
+ File dir = new File(newDirURL.getFile());
+ dir.mkdirs();
+ inStream = contentReference.getInputStream();
+ nonPluginArchivePath =
+ new File(dir, contentReference.getIdentifier());
+ UpdateManagerUtils.copyToLocal(
+ inStream,
+ nonPluginArchivePath.getAbsolutePath(),
+ null);
+ } catch (IOException e) {
+ throw Utilities.newCoreException(
+ "Error occurred while creating "+ nonPluginArchivePath.getAbsolutePath()+" file." //$NON-NLS-1$ //$NON-NLS-2$
+ ,e);
+ } finally {
+ if (inStream != null) {
+ try {
+ inStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ private void save() {
+ FileOutputStream fos = null;
+ try {
+ URL siteURL = new URL(this.getURL(), "site.xml"); //$NON-NLS-1$
+ fos = new FileOutputStream(new File(siteURL.getFile()));
+ OutputStreamWriter outWriter = new OutputStreamWriter(fos, "UTF-8"); //$NON-NLS-1$
+ PrintWriter writer = new PrintWriter(outWriter);
+ save(writer);
+ writer.flush();
+ } catch (IOException ioe) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(
+ Utilities.newCoreException(
+ "Site XML could not be saved.", //$NON-NLS-1$
+ ioe));
+ } finally {
+ if (fos != null) {
+ try {
+ fos.close();
+ } catch (IOException ioe2) {
+ }
+ }
+ }
+ }
+ private void save(PrintWriter writer) {
+ writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); //$NON-NLS-1$
+ //writer.println("<!DOCTYPE site SYSTEM \"dtd/site.dtd\">");
+ writeSite("", writer); //$NON-NLS-1$
+ }
+
+ private void writeSite(String indent, PrintWriter writer) {
+ writer.print(indent + "<site"); //$NON-NLS-1$
+ String indent2 = indent + INDENT;
+ // default type
+ //writeIfDefined(indenta, writer, "type", getType());
+ // stored relative to site.xml
+ //writeIfDefined(indenta, writer, "url", getURL());
+ writer.println(">"); //$NON-NLS-1$
+ URLEntryModel description = getDescriptionModel();
+ if (description != null) {
+ writer.println();
+ writeDescription(indent2, writer, description);
+ writer.println();
+ }
+ writeFeatures(indent2, writer);
+ writeCategories(indent2, writer);
+ writer.println(indent + "</site>"); //$NON-NLS-1$
+ }
+ private void writeFeatures(String indent, PrintWriter writer) {
+ SiteFeatureReferenceModel[] featureReferenceModels =
+ getFeatureReferenceModels();
+ for (int i = 0; i < featureReferenceModels.length; i++) {
+ writer.print(indent);
+ writer.print("<feature"); //$NON-NLS-1$
+ writer.print(
+ " url=\"features/" //$NON-NLS-1$
+ + featureReferenceModels[i].getFeatureIdentifier()
+ + "_" //$NON-NLS-1$
+ + featureReferenceModels[i].getFeatureVersion()
+ + ".jar\""); //$NON-NLS-1$
+ writer.print(
+ " id=\"" //$NON-NLS-1$
+ + featureReferenceModels[i].getFeatureIdentifier()
+ + "\""); //$NON-NLS-1$
+ writer.print(
+ " version=\"" //$NON-NLS-1$
+ + featureReferenceModels[i].getFeatureVersion()
+ + "\""); //$NON-NLS-1$
+ writer.println(">"); //$NON-NLS-1$
+
+ String[] categoryNames =
+ featureReferenceModels[i].getCategoryNames();
+ for (int cn = 0; cn < categoryNames.length; cn++) {
+ writer.print(indent + INDENT);
+ writer.println(
+ "<category name=\"" + categoryNames[cn] + "\" />"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ }
+
+ writer.print(indent);
+ writer.println("</feature>"); //$NON-NLS-1$
+ writer.println();
+ }
+ }
+ private void writeCategories(String indent, PrintWriter writer) {
+ CategoryModel[] categoryModels = getCategoryModels();
+ if (categoryModels.length <= 0) {
+ return;
+ }
+ for (int i = 0; i < categoryModels.length; i++) {
+ writer.print(indent);
+ writer.print("<category-def"); //$NON-NLS-1$
+ writer.print(
+ " name=\"" //$NON-NLS-1$
+ + categoryModels[i].getName()
+ + "\" label=\"" //$NON-NLS-1$
+ + categoryModels[i].getLabel()
+ + "\""); //$NON-NLS-1$
+ writer.println(">"); //$NON-NLS-1$
+ if (categoryModels[i].getDescriptionModel() != null) {
+ writeDescription(
+ indent + INDENT,
+ writer,
+ categoryModels[i].getDescriptionModel());
+ }
+ writer.print(indent);
+ writer.println("</category-def>"); //$NON-NLS-1$
+ writer.println();
+ }
+ }
+ private void writeDescription(
+ String indent,
+ PrintWriter writer,
+ URLEntryModel urlEntryModel) {
+ String url = urlEntryModel.getURLString();
+ String text = urlEntryModel.getAnnotationNonLocalized();
+ writer.print(indent);
+ writer.print("<description"); //$NON-NLS-1$
+ if (url != null)
+ writer.print(" url=\"" + url + "\""); //$NON-NLS-1$ //$NON-NLS-2$
+ if (text == null || text.length() <= 0) {
+ writer.println(" />"); //$NON-NLS-1$
+ } else {
+ writer.println(">"); //$NON-NLS-1$
+ if (text != null) {
+ writer.println(
+ indent + INDENT + UpdateManagerUtils.xmlSafe(text));
+ }
+ writer.println(indent + "</description>"); //$NON-NLS-1$
+ }
+ }
+ /**
+ * Adds a plugin entry
+ * Either from parsing the file system or
+ * installing a feature
+ *
+ * We cannot figure out the list of plugins by reading the Site.xml as
+ * the archives tag are optionals
+ */
+ public void addDownloadedPluginEntry(IPluginEntry pluginEntry) {
+ downloadedPluginEntries.add(pluginEntry);
+ }
+
+ private IPluginEntry[] getDownloadedPluginEntries() {
+ return (IPluginEntry[]) downloadedPluginEntries.toArray(
+ new IPluginEntry[downloadedPluginEntries.size()]);
+ }
+ /**
+ * Adds a plugin entry
+ * Either from parsing the file system or
+ * installing a feature
+ *
+ * We cannot figure out the list of plugins by reading the Site.xml as
+ * the archives tag are optionals
+ */
+ public void addDownloadedFeatureReferenceModel(SiteFeatureReferenceModel featureModel) {
+ downloadedFeatureReferenceModels.add(featureModel);
+ }
+
+ private SiteFeatureReferenceModel[] getDownloadedFeatureReferenceModels() {
+ return (
+ SiteFeatureReferenceModel[]) downloadedFeatureReferenceModels
+ .toArray(
+ new SiteFeatureReferenceModel[downloadedFeatureReferenceModels
+ .size()]);
+ }
+ /**
+ * Checks if mirror site contains a feature with given ID and version
+ * @param featureRefModel
+ * @return true if such feature exists
+ */
+ /*private boolean contains(SiteFeatureReferenceModel featureRefModel) {
+ ISiteFeatureReference featureRefs[] = getRawFeatureReferences();
+ for (int i = 0; i < featureRefs.length; i++) {
+ try {
+ if (featureRefs[i]
+ .getVersionedIdentifier()
+ .equals(featureRefModel.getVersionedIdentifier())) {
+ return true;
+ }
+ } catch (CoreException ce) {
+ ce.printStackTrace();
+ }
+ }
+ return false;
+ }*/
+
+ /**
+ * Updates description of this site
+ * from description of the remote site.
+ */
+ private void updateDescription(ISite remoteSite) {
+ IURLEntry urlEntry = remoteSite.getDescription();
+ if (urlEntry != null) {
+ URLEntryModel newUrlEntryModel = new URLEntryModel();
+ URL url = urlEntry.getURL();
+ newUrlEntryModel.setAnnotation(urlEntry.getAnnotation());
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=136249
+ // URL is not required, so might be null
+ // The null case is (already) handled correctly in
+ // writeDescription
+ if (url != null) {
+ newUrlEntryModel.setURLString(url.toExternalForm());
+ }
+ this.setDescriptionModel(newUrlEntryModel);
+ }
+ }
+ /**
+ * Updates all categories used by features on this site
+ * from categories defined on remote site.
+ * Categories not defined on remote site are unchanged.
+ */
+ private void updateCategories(ISite remoteSite) {
+ // collect name of categories used on this site
+ Set usedCategoryNames = new HashSet();
+ SiteFeatureReferenceModel featureRefModels[] =
+ getFeatureReferenceModels();
+ for (int f = 0; f < featureRefModels.length; f++) {
+ String[] featureCategoryNames =
+ featureRefModels[f].getCategoryNames();
+
+ for (int c = 0; c < featureCategoryNames.length; c++) {
+ usedCategoryNames.add(featureCategoryNames[c]);
+ }
+ }
+
+ Collection newCategoryModels = new ArrayList();
+ for (Iterator it = usedCategoryNames.iterator(); it.hasNext();) {
+ String name = (String) it.next();
+ ICategory remoteCategory = remoteSite.getCategory(name);
+ if (remoteCategory == null) {
+ // remote site does not define this category
+ CategoryModel oldCategory = null;
+ try {
+ oldCategory = (CategoryModel) getCategory(name);
+ } catch (NullPointerException npe) {
+ // cannot reproduce npe anymore
+ }
+ if (oldCategory != null) {
+ newCategoryModels.add(oldCategory);
+ }
+ } else {
+ newCategoryModels.add(remoteCategory);
+ }
+
+ }
+ setCategoryModels(
+ (CategoryModel[]) newCategoryModels.toArray(
+ new CategoryModel[newCategoryModels.size()]));
+
+ }
+ private void generateUpdatePolicy(String url) {
+ FileOutputStream fos = null;
+ try {
+ URL siteURL = new URL(this.getURL(), "policy.xml"); //$NON-NLS-1$
+ fos = new FileOutputStream(new File(siteURL.getFile()));
+ OutputStreamWriter outWriter = new OutputStreamWriter(fos, "UTF-8"); //$NON-NLS-1$
+ PrintWriter writer = new PrintWriter(outWriter);
+
+ writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); //$NON-NLS-1$
+ writer.println("<update-policy>"); //$NON-NLS-1$
+
+ writer.println(
+ "<!-- You can paste the following fragment, containing url-map elements, into another policy file. -->"); //$NON-NLS-1$
+ writeUrlMaps(writer, url);
+ writer.println("<!-- End of fragment with url-map elements. -->"); //$NON-NLS-1$
+
+ writer.println("</update-policy>"); //$NON-NLS-1$
+
+ writer.flush();
+ } catch (IOException ioe) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(
+ Utilities.newCoreException(
+ "policy.xml could not be saved", //$NON-NLS-1$
+ ioe));
+ } finally {
+ if (fos != null) {
+ try {
+ fos.close();
+ } catch (IOException ioe2) {
+ }
+ }
+ }
+ }
+ private void writeUrlMaps(PrintWriter writer, String url) {
+ SiteFeatureReferenceModel[] featureReferenceModels =
+ getFeatureReferenceModels();
+ for (int i = 0; i < featureReferenceModels.length; i++) {
+ writer.print("\t"); //$NON-NLS-1$
+ writer.print("<url-map"); //$NON-NLS-1$
+ writer.print(
+ " pattern=\"" //$NON-NLS-1$
+ + featureReferenceModels[i].getFeatureIdentifier()
+ + "\""); //$NON-NLS-1$
+ writer.print(" url=\"" + url + "\""); //$NON-NLS-1$ //$NON-NLS-2$
+ writer.println(" />"); //$NON-NLS-1$
+ }
+ }
+
+ public void setIgnoreNonPresentPlugins(boolean ignoreNonPresentPlugins) {
+ this.ignoreNonPresentPlugins = ignoreNonPresentPlugins;
+
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/mirror/MirrorSiteFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/mirror/MirrorSiteFactory.java
new file mode 100644
index 0000000..482ab68
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/mirror/MirrorSiteFactory.java
@@ -0,0 +1,234 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.mirror;
+import java.io.*;
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.core.model.*;
+import org.eclipse.update.internal.core.*;
+import org.eclipse.update.internal.model.*;
+import org.eclipse.update.standalone.*;
+import org.xml.sax.*;
+
+public class MirrorSiteFactory extends BaseSiteFactory {
+ /*
+ * @see SiteModelFactory#createSiteMapModel()
+ */
+ public SiteModel createSiteMapModel() {
+ return new MirrorSite(this);
+ }
+ /*
+ * @see ISiteFactory#createSite(URL)
+ */
+ public ISite createSite(URL url)
+ throws CoreException, InvalidSiteTypeException {
+ return createSite(new File(url.getFile()));
+ }
+ /*
+ * @see ISiteFactory#createSite(URL)
+ */
+ public ISite createSite(File siteLocation)
+ throws CoreException, InvalidSiteTypeException {
+
+ InputStream siteStream = null;
+
+ if (!siteLocation.exists()) {
+ if (!siteLocation.mkdirs()) {
+ throw Utilities.newCoreException(
+ "Directory " //$NON-NLS-1$
+ + siteLocation.getAbsolutePath()
+ + " could not be created.", //$NON-NLS-1$
+ null);
+ }
+ }
+ if (!siteLocation.isDirectory() || !siteLocation.canWrite())
+ throw Utilities.newCoreException(
+ siteLocation.getAbsolutePath()
+ + " is not a directory or is not writtable.", //$NON-NLS-1$
+ null);
+
+ MirrorSite site = null;
+ // parse public features
+ if (new File(siteLocation, Site.SITE_XML).exists()) {
+ try {
+ siteStream =
+ new FileInputStream(new File(siteLocation, Site.SITE_XML));
+ } catch (FileNotFoundException fnfe) {
+ }
+ site = (MirrorSite) parseSite(siteStream);
+ try {
+ if (siteStream != null)
+ siteStream.close();
+ } catch (IOException e) {
+ }
+ }
+ if (site == null) {
+ site = (MirrorSite) createSiteMapModel();
+ }
+ // parse downloaded plugins and fragments
+ parseDownloadedPluginsAndFragments(
+ site,
+ new File(siteLocation, Site.DEFAULT_PLUGIN_PATH));
+ // parse downloaded features
+ parseDownloadedFeatures(
+ site,
+ new File(siteLocation, Site.DEFAULT_FEATURE_PATH));
+
+ URL url;
+ try {
+ url = siteLocation.toURL();
+ } catch (MalformedURLException mue) {
+ throw Utilities.newCoreException(
+ "A URL for site " //$NON-NLS-1$
+ + siteLocation.getAbsolutePath()
+ + " could not be created.", //$NON-NLS-1$
+ mue);
+ }
+ SiteContentProvider contentProvider = null;
+ contentProvider = new SiteFileContentProvider(url);
+
+ site.setSiteContentProvider(contentProvider);
+ contentProvider.setSite(site);
+ try {
+ site.resolve(url, url);
+ } catch (MalformedURLException mue) {
+ throw Utilities.newCoreException(
+ "Unable to resolve URL " //$NON-NLS-1$
+ + (url == null ? "" : url.toExternalForm()), //$NON-NLS-1$
+ mue);
+ }
+ return site;
+ }
+ /**
+ *
+ */
+ private void parseDownloadedPluginsAndFragments(MirrorSite site,
+ File pluginDir) throws CoreException {
+ if (!pluginDir.exists()) {
+ return;
+ }
+ String[] dir = pluginDir.list(FeaturePackagedContentProvider.filter);
+ for (int i = 0; i < dir.length; i++) {
+ InputStream in = null;
+ try {
+ File file = new File(pluginDir, dir[i]);
+ JarContentReference jarReference = new JarContentReference(
+ null, file);
+ ContentReference ref = jarReference.peek("META-INF/MANIFEST.MF", null, null); //$NON-NLS-1$
+ if (ref != null) {
+ try {
+ in = ref.getInputStream();
+ }
+ catch (SecurityException e) {
+ // in case of an invalid signature in jar, we will catch
+ // and re-throw a little more specific message. Otherwise, it's
+ // impossible to tell which jar had the problem.
+ String filename = file.getName();
+ CoreException updateException = Utilities.newCoreException(filename,e);
+ throw updateException;
+ }
+ BundleManifest manifest = new BundleManifest(in);
+ if (manifest.exists()) {
+ site
+ .addDownloadedPluginEntry(manifest
+ .getPluginEntry());
+ continue;
+ }
+ }
+ ref = jarReference.peek("plugin.xml", null, null); //$NON-NLS-1$
+ if (ref == null) {
+ ref = jarReference.peek("fragment.xml", null, null); //$NON-NLS-1$
+ }
+ if (ref != null) {
+ in = ref.getInputStream();
+ PluginEntry entry = new DefaultPluginParser().parse(in);
+ site.addDownloadedPluginEntry(entry);
+ }
+ } catch (IOException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ } catch (SAXException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ } finally {
+ if(in !=null){
+ try{
+ in.close();
+ }catch(IOException ce){
+ }
+ }
+ }
+ }
+ }
+ /**
+ * Method parseFeature.
+ * @throws CoreException
+ */
+ private void parseDownloadedFeatures(MirrorSite site, File featureDir)
+ throws CoreException {
+ if (featureDir.exists()) {
+ String[] dir;
+ SiteFeatureReferenceModel featureRef;
+ URL featureURL;
+ File currentFeatureFile;
+ String newFilePath = null;
+
+ try {
+ // only list JAR files
+ dir = featureDir.list(FeaturePackagedContentProvider.filter);
+ for (int index = 0; index < dir.length; index++) {
+
+ // check if the JAR file contains a feature.xml
+ currentFeatureFile = new File(featureDir, dir[index]);
+ JarContentReference ref =
+ new JarContentReference("", currentFeatureFile); //$NON-NLS-1$
+ ContentReference result = null;
+ try {
+ result = ref.peek(Feature.FEATURE_XML, null, null);
+ } catch (IOException e) {
+ UpdateCore.warn(
+ "Exception retrieving feature.xml in file:" //$NON-NLS-1$
+ + currentFeatureFile,
+ e);
+ }
+ if (result == null) {
+ UpdateCore.warn(
+ "Unable to find feature.xml in file:" //$NON-NLS-1$
+ + currentFeatureFile);
+ } else {
+ featureURL = currentFeatureFile.toURL();
+ featureRef = createFeatureReferenceModel();
+ featureRef.setSiteModel(site);
+ featureRef.setURLString(featureURL.toExternalForm());
+ featureRef.setType(ISite.DEFAULT_PACKAGED_FEATURE_TYPE);
+ featureRef.setFeatureIdentifier(
+ featureRef
+ .getVersionedIdentifier()
+ .getIdentifier());
+ featureRef.setFeatureVersion(
+ featureRef
+ .getVersionedIdentifier()
+ .getVersion()
+ .toString());
+ site.addDownloadedFeatureReferenceModel(featureRef);
+ }
+ }
+ } catch (MalformedURLException e) {
+ throw Utilities.newCoreException(
+ "Unable to create URL for file " + newFilePath + ".", //$NON-NLS-1$ //$NON-NLS-2$
+ e);
+ }
+ }
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/BundleManifest.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/BundleManifest.java
new file mode 100644
index 0000000..fbbeeee
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/BundleManifest.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.model;
+import java.io.*;
+import java.util.jar.*;
+
+import org.eclipse.osgi.util.*;
+import org.eclipse.update.core.*;
+import org.osgi.framework.*;
+/**
+ * Parses MANIFEST.MF
+ */
+public class BundleManifest {
+ private PluginEntry pluginEntry;
+ private IOException exception;
+ /**
+ * Constructor for local file
+ */
+public BundleManifest(File manifest) {
+ super();
+ if (manifest.exists() && !manifest.isDirectory()) {
+ FileInputStream fos = null;
+ try {
+ fos = new FileInputStream(manifest);
+ parse(fos);
+ } catch (IOException ioe) {
+ } finally {
+ if (fos != null) {
+ try {
+ fos.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+ }
+ /**
+ * Constructor for local file
+ */
+ public BundleManifest(InputStream input) {
+ super();
+ if (input != null) {
+ parse(input);
+ }
+ }
+ /**
+ * Parses manifest, creates PluginEntry if manifest is valid, stores
+ * exception if any occurs
+ *
+ * @param in
+ * InputStream
+ */
+ private void parse(InputStream in) {
+ try {
+ Manifest m = new Manifest(in);
+ Attributes a = m.getMainAttributes();
+ // plugin id
+ String symbolicName = a.getValue(Constants.BUNDLE_SYMBOLICNAME);
+ if (symbolicName == null) {
+ // In Eclipse manifest must have Bundle-SymbolicName attribute
+ return;
+ }
+ String id;
+ try {
+ ManifestElement[] elements = ManifestElement.parseHeader(
+ Constants.BUNDLE_SYMBOLICNAME, symbolicName);
+ id = elements[0].getValue();
+ } catch (BundleException be) {
+ throw new IOException(be.getMessage());
+ }
+ // plugin version
+ String version = a.getValue(Constants.BUNDLE_VERSION);
+ if (version == null) {
+ return;
+ }
+ String hostPlugin = a.getValue(Constants.FRAGMENT_HOST);
+ pluginEntry = new PluginEntry();
+ pluginEntry.setVersionedIdentifier(new VersionedIdentifier(id,
+ version));
+ pluginEntry.isFragment(hostPlugin != null
+ && hostPlugin.length() > 0);
+ } catch (IOException ioe) {
+ exception = ioe;
+ }
+ }
+ public boolean exists() {
+ return exception != null || pluginEntry != null;
+ }
+ /**
+ * Obtains PluginEntry from a manifest.
+ *
+ * @return PluginEntry or null if valid manifest does not exist
+ * @throws IOException
+ * if exception during parsing
+ */
+ public PluginEntry getPluginEntry() throws IOException {
+ if (exception != null) {
+ throw exception;
+ } else {
+ return pluginEntry;
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/ConfigurationActivityModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/ConfigurationActivityModel.java
new file mode 100644
index 0000000..faf1b63
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/ConfigurationActivityModel.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.model;
+
+import java.util.Date;
+
+import org.eclipse.update.core.model.*;
+
+public class ConfigurationActivityModel extends ModelObject{
+
+ private String label;
+ private int action;
+ private Date date;
+ private int status;
+ private InstallConfigurationModel installConfiguration;
+
+
+ /**
+ * Constructor for ConfigurationActivityModel.
+ */
+ public ConfigurationActivityModel() {
+ super();
+ }
+
+ /**
+ * @since 2.0
+ */
+ public int getAction() {
+ return action;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public Date getDate() {
+ return date;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public int getStatus() {
+ return status;
+ }
+
+ /**
+ * Sets the date.
+ * @param date The date to set
+ */
+ public void setDate(Date date) {
+ assertIsWriteable();
+ this.date = date;
+ }
+
+ /**
+ * Sets the status.
+ * @param status The status to set
+ */
+ public void setStatus(int status) {
+ assertIsWriteable();
+ this.status = status;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Sets the label.
+ * @param label The label to set
+ */
+ public void setLabel(String label) {
+ assertIsWriteable();
+ this.label = label;
+ }
+
+ /**
+ * Sets the action.
+ * @param action The action to set
+ */
+ public void setAction(int action) {
+ assertIsWriteable();
+ this.action = action;
+ }
+
+ /**
+ * Gets the installConfiguration.
+ * @return Returns a InstallConfigurationModel
+ */
+ public InstallConfigurationModel getInstallConfigurationModel() {
+ return installConfiguration;
+ }
+
+ /**
+ * Sets the installConfiguration.
+ * @param installConfiguration The installConfiguration to set
+ */
+ public void setInstallConfigurationModel(InstallConfigurationModel installConfiguration) {
+ assertIsWriteable();
+ this.installConfiguration = installConfiguration;
+ }
+
+}
+
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/ConfigurationPolicyModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/ConfigurationPolicyModel.java
new file mode 100644
index 0000000..34e5116
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/ConfigurationPolicyModel.java
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.model;
+
+import java.net.*;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.update.core.*;
+import org.eclipse.update.core.model.*;
+import org.eclipse.update.internal.core.*;
+
+/**
+ *
+ */
+public class ConfigurationPolicyModel extends ModelObject {
+
+
+
+
+ private int policy;
+ private Map /* of FeatureReferenceModel */configuredFeatureReferences;
+ private Map /* of FeatureReferenceModel */unconfiguredFeatureReferences;
+
+ // since 2.0.2
+ private ConfiguredSiteModel configuredSiteModel;
+
+ // since 2.1
+ private boolean enable;
+
+ /**
+ * Constructor for ConfigurationPolicyModel.
+ */
+ public ConfigurationPolicyModel() {
+ super();
+ enable = true;
+ configuredFeatureReferences = new HashMap();
+// unconfiguredFeatureReferences = new HashMap();
+ }
+
+ /**
+ * @since 2.0
+ */
+ public int getPolicy() {
+ return policy;
+ }
+
+ /**
+ * Sets the policy.
+ * @param policy The policy to set
+ */
+ public void setPolicy(int policy) {
+ assertIsWriteable();
+ this.policy = policy;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public FeatureReferenceModel[] getConfiguredFeaturesModel() {
+ if (configuredFeatureReferences==null || configuredFeatureReferences.isEmpty())
+ return new FeatureReferenceModel[0];
+ return (FeatureReferenceModel[]) configuredFeatureReferences.keySet().toArray(arrayTypeFor(configuredFeatureReferences.keySet()));
+ }
+
+ /**
+ * @since 2.0
+ */
+ public FeatureReferenceModel[] getUnconfiguredFeaturesModel() {
+ // obtain unconfigured features by comparing configured ones with those installed
+ if (unconfiguredFeatureReferences == null
+ && configuredSiteModel != null
+ && configuredSiteModel.getSiteModel() != null) {
+ ISite site = (ISite) configuredSiteModel.getSiteModel();
+ ISiteFeatureReference[] siteFeatures = site.getFeatureReferences();
+ if (siteFeatures.length > getConfiguredFeaturesModel().length) {
+ for (int i=0; i<siteFeatures.length; i++) {
+ if (!(siteFeatures[i] instanceof SiteFeatureReference))
+ continue;
+ Iterator iterator = configuredFeatureReferences.keySet().iterator();
+ boolean found = false;
+ while(!found && iterator.hasNext()) {
+ FeatureReferenceModel f = (FeatureReferenceModel)iterator.next();
+ if (UpdateManagerUtils.sameURL(f.getURL(), siteFeatures[i].getURL()))
+ found = true;
+ }
+ if (!found)
+ addUnconfiguredFeatureReference((SiteFeatureReference)siteFeatures[i]);
+ }
+ }
+ }
+ if (unconfiguredFeatureReferences == null
+ || unconfiguredFeatureReferences.isEmpty())
+ return new FeatureReferenceModel[0];
+ return (FeatureReferenceModel[]) unconfiguredFeatureReferences.keySet()
+ .toArray(arrayTypeFor(unconfiguredFeatureReferences.keySet()));
+ }
+
+ /**
+ * Gets the configuredSiteModel.
+ * @return Returns a ConfiguredSiteModel
+ * @since 2.0.2
+ */
+ public ConfiguredSiteModel getConfiguredSiteModel() {
+ return configuredSiteModel;
+ }
+
+ /**
+ * Sets the configuredSiteModel.
+ * @param configuredSiteModel The configuredSiteModel to set
+ * @since 2.0.2
+ */
+ public void setConfiguredSiteModel(ConfiguredSiteModel configuredSiteModel) {
+ this.configuredSiteModel = configuredSiteModel;
+ }
+
+ /**
+ *
+ */
+ private boolean remove(FeatureReferenceModel feature, Map list) {
+ URL featureURL = feature.getURL();
+ boolean found = false;
+ Iterator iter = list.keySet().iterator();
+ while (iter.hasNext() && !found) {
+ FeatureReferenceModel element = (FeatureReferenceModel) iter.next();
+ if (UpdateManagerUtils.sameURL(element.getURL(),featureURL)) {
+ list.remove(element);
+ found = true;
+ }
+ }
+ return found;
+ }
+
+ /**
+ * returns an array of string corresponding to plugins file
+ */
+ /*package*/
+
+
+ /**
+ *
+ */
+ private void add(FeatureReferenceModel feature, Map list) {
+ URL featureURL = feature.getURL();
+ boolean found = false;
+ Iterator iter = list.keySet().iterator();
+ while (iter.hasNext() && !found) {
+ FeatureReferenceModel element = (FeatureReferenceModel) iter.next();
+ if (UpdateManagerUtils.sameURL(element.getURL(),featureURL)) {
+ found = true;
+ }
+ }
+
+ if (!found) {
+ list.put(feature,null);
+ } else {
+ UpdateCore.warn("Feature Reference :"+feature+" already part of the list."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * adds a feature in the configuredReference list
+ * also used by the parser to avoid creating another activity
+ */
+ public void addConfiguredFeatureReference(FeatureReferenceModel feature) {
+ assertIsWriteable();
+
+ if (configuredFeatureReferences == null)
+ this.configuredFeatureReferences = new HashMap();
+ if (!configuredFeatureReferences.containsKey(feature)){
+ //DEBUG:
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION){
+ UpdateCore.debug("Configuring "+feature.getURLString()); //$NON-NLS-1$
+ }
+ this.add(feature, configuredFeatureReferences);
+ }
+
+ // when user configure a feature,
+ // we have to remove it from unconfigured feature if it exists
+ // because the user doesn't know...
+ if (unconfiguredFeatureReferences != null) {
+ boolean success = remove(feature, unconfiguredFeatureReferences);
+ if (!success)
+ UpdateCore.warn("Feature not part of Unconfigured list: "+feature.getURLString()); //$NON-NLS-1$
+ }
+
+ }
+
+ /**
+ * adds a feature in the list
+ * also used by the parser to avoid creating another activity
+ */
+ public void addUnconfiguredFeatureReference(FeatureReferenceModel feature) {
+ assertIsWriteable();
+ if (unconfiguredFeatureReferences == null)
+ this.unconfiguredFeatureReferences = new HashMap();
+ if (!unconfiguredFeatureReferences.containsKey(feature)){
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION){
+ UpdateCore.debug("Unconfiguring "+feature.getURLString()); //$NON-NLS-1$
+ }
+ this.add(feature, unconfiguredFeatureReferences);
+ }
+
+ // an unconfigured feature is always from a configured one no ?
+ // unless it was parsed right ?
+ if (configuredFeatureReferences != null) {
+ boolean success = remove(feature, configuredFeatureReferences);
+ if (!success)
+ UpdateCore.warn("Feature not part of Configured list: "+feature.getURLString()); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * removes a feature from any list
+ */
+ public void removeFeatureReference(FeatureReferenceModel feature) {
+ assertIsWriteable();
+ if (unconfiguredFeatureReferences!=null){
+ boolean success = remove(feature, unconfiguredFeatureReferences);
+ if (!success)
+ UpdateCore.warn(feature.getURLString()+" not part of unconfigured list."); //$NON-NLS-1$
+ }
+
+ if (configuredFeatureReferences != null) {
+ boolean success = remove(feature, configuredFeatureReferences);
+ if (!success)
+ UpdateCore.warn(feature.getURLString()+" not part of configured list."); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Sets the unconfiguredFeatureReferences.
+ * @param featureReferences The unconfiguredFeatureReferences to set
+ */
+ protected void setUnconfiguredFeatureReferences(IFeatureReference[] featureReferences) {
+ unconfiguredFeatureReferences = new HashMap();
+ for (int i = 0; i < featureReferences.length; i++) {
+ unconfiguredFeatureReferences.put(featureReferences[i],null);
+ }
+ }
+
+
+ /**
+ * Sets the configuredFeatureReferences.
+ * @param featureReferences The configuredFeatureReferences to set
+ */
+ protected void setConfiguredFeatureReferences(IFeatureReference[] featureReferences) {
+ configuredFeatureReferences = new HashMap();
+ for (int i = 0; i < featureReferences.length; i++) {
+ configuredFeatureReferences.put(featureReferences[i],null);
+ }
+
+ }
+
+ /**
+ * @return boolean
+ */
+ public boolean isEnabled() {
+ return enable;
+ }
+
+ /**
+ * @param value
+ */
+ public void setEnabled(boolean value) {
+ enable = value;
+ }
+
+
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/ConfiguredSiteModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/ConfiguredSiteModel.java
new file mode 100644
index 0000000..a45b2c4
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/ConfiguredSiteModel.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.model;
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.model.*;
+import org.eclipse.update.internal.core.*;
+
+/**
+ *
+ */
+public class ConfiguredSiteModel extends ModelObject {
+ private String[] previousPluginPath;
+
+ private SiteModel site;
+ private String platformURLString;
+ private ConfigurationPolicyModel policy;
+ private InstallConfigurationModel installConfiguration;
+ private boolean installable = false;
+
+ /**
+ * Constructor
+ */
+ public ConfiguredSiteModel() {
+ super();
+ }
+
+ /**
+ * returns the site
+ * @return The ISite
+ * @since 2.0
+ */
+ public SiteModel getSiteModel() {
+ return site;
+ }
+
+ /**
+ * Sets the site.
+ * @param site The site to set
+ */
+ public void setSiteModel(SiteModel site) {
+ assertIsWriteable();
+ this.site = site;
+ }
+
+ /**
+ * returns the policy
+ */
+ public ConfigurationPolicyModel getConfigurationPolicyModel() {
+ return policy;
+ }
+
+ /**
+ *
+ * @since 2.0
+ */
+ public void setConfigurationPolicyModel(ConfigurationPolicyModel policy) {
+ assertIsWriteable();
+ this.policy = policy;
+ policy.setConfiguredSiteModel(this);
+ }
+
+ /**
+ * @since
+ */
+ public boolean isUpdatable() {
+ return installable;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void setUpdatable(boolean installable) {
+ assertIsWriteable();
+ this.installable = installable;
+ }
+
+ /**
+ * Gets the installConfiguration.
+ * @return Returns a InstallConfigurationModel
+ */
+ public InstallConfigurationModel getInstallConfigurationModel() {
+ return installConfiguration;
+ }
+
+ /**
+ * Sets the installConfiguration.
+ * @param installConfiguration The installConfiguration to set
+ */
+ public void setInstallConfigurationModel(InstallConfigurationModel installConfiguration) {
+ assertIsWriteable();
+ this.installConfiguration = installConfiguration;
+ }
+
+ /**
+ * Gets the platformURLString.
+ * @return Returns a String
+ */
+ public String getPlatformURLString() {
+ return platformURLString;
+ }
+
+ /**
+ * Sets the platformURLString.
+ * @param platformURLString The platformURLString to set
+ */
+ public void setPlatformURLString(String platformURLString) {
+ this.platformURLString = platformURLString;
+ }
+
+
+ /**
+ * Gets the previousPluginPath. The list of plugins the platform had.
+ * @return Returns a String[]
+ */
+ public String[] getPreviousPluginPath() {
+ if (previousPluginPath == null)
+ previousPluginPath = new String[0];
+ return previousPluginPath;
+ }
+
+ /**
+ * Sets the previousPluginPath.
+ * @param previousPluginPath The previousPluginPath to set
+ */
+ public void setPreviousPluginPath(String[] previousPluginPath) {
+ this.previousPluginPath = new String[previousPluginPath.length];
+ System.arraycopy(previousPluginPath, 0, this.previousPluginPath, 0, previousPluginPath.length);
+ }
+
+ /*
+ * creates a Status
+ */
+ protected IStatus createStatus(int statusType, String msg, Exception e){
+ if (statusType!=IStatus.OK) statusType = IStatus.ERROR;
+ return createStatus(statusType,IStatus.OK, msg.toString(), e);
+ }
+
+ /*
+ * creates a Status
+ */
+ protected IStatus createStatus(int statusSeverity, int statusCode, String msg, Exception e){
+ String id = UpdateCore.getPlugin().getBundle().getSymbolicName();
+
+ StringBuffer completeString = new StringBuffer(""); //$NON-NLS-1$
+ if (msg!=null)
+ completeString.append(msg);
+ if (e!=null){
+ completeString.append("\r\n["); //$NON-NLS-1$
+ completeString.append(e.toString());
+ completeString.append("]\r\n"); //$NON-NLS-1$
+ }
+ return new Status(statusSeverity, id, statusCode, completeString.toString(), e);
+ }
+
+ /**
+ * @see org.eclipse.update.configuration.IConfiguredSite#isEnabled()
+ */
+ public boolean isEnabled() {
+ return getConfigurationPolicyModel().isEnabled();
+ }
+
+ /**
+ * @see org.eclipse.update.configuration.IConfiguredSite#setEnabled(boolean)
+ */
+ public void setEnabled(boolean value) {
+ getConfigurationPolicyModel().setEnabled(value);
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/DefaultPluginParser.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/DefaultPluginParser.java
new file mode 100644
index 0000000..f406130
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/DefaultPluginParser.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.model;
+
+
+import java.io.*;
+import javax.xml.parsers.*;
+
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.*;
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+/**
+ * Parse default feature.xml
+ */
+
+public class DefaultPluginParser extends DefaultHandler {
+ private final static SAXParserFactory parserFactory =
+ SAXParserFactory.newInstance();
+ private SAXParser parser;
+ private String id = null;
+ private String version = null;
+ private PluginEntry pluginEntry;
+
+ private static final String PLUGIN = "plugin"; //$NON-NLS-1$
+ private static final String FRAGMENT = "fragment"; //$NON-NLS-1$
+
+ private class ParseCompleteException extends SAXException {
+
+ private static final long serialVersionUID = 1L;
+
+ public ParseCompleteException(String arg0) {
+ super(arg0);
+ }
+ }
+
+ /**
+ * Constructor for DefaultFeatureParser
+ */
+ public DefaultPluginParser() {
+ super();
+ try {
+ parserFactory.setNamespaceAware(true);
+ this.parser = parserFactory.newSAXParser();
+ } catch (ParserConfigurationException e) {
+ UpdateCore.log(e);
+ } catch (SAXException e) {
+ UpdateCore.log(e);
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized PluginEntry parse(InputStream in) throws SAXException, IOException {
+ try {
+ pluginEntry = new PluginEntry();
+ parser.parse(new InputSource(in), this);
+ } catch (ParseCompleteException e) {
+ // expected, we stopped the parsing when we have the information we need
+ /// no need to pursue the parsing
+ }
+
+ if (id == null || id.trim().length() == 0)
+ id = "_no_id_"; //$NON-NLS-1$
+ pluginEntry.setVersionedIdentifier(new VersionedIdentifier(id, version));
+ return pluginEntry;
+ }
+
+ /**
+ * @see DefaultHandler#startElement(String, String, String, Attributes)
+ */
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+
+ String tag = localName.trim();
+
+ if (tag.equalsIgnoreCase(PLUGIN)) {
+ pluginEntry.isFragment(false);
+ processPlugin(attributes);
+ return;
+ }
+
+ if (tag.equalsIgnoreCase(FRAGMENT)) {
+ pluginEntry.isFragment(true);
+ processPlugin(attributes);
+ return;
+ }
+ }
+
+ /**
+ * process plugin entry info
+ */
+ private void processPlugin(Attributes attributes) throws ParseCompleteException {
+ id = attributes.getValue("id"); //$NON-NLS-1$
+ version = attributes.getValue("version"); //$NON-NLS-1$
+ throw new ParseCompleteException(""); //$NON-NLS-1$
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/ITimestamp.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/ITimestamp.java
new file mode 100644
index 0000000..246287b
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/ITimestamp.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.model;
+
+import java.util.Date;
+
+public interface ITimestamp {
+
+ public Date getTimestamp();
+
+ public void setTimestamp( Date timestamp);
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/InstallConfigurationModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/InstallConfigurationModel.java
new file mode 100644
index 0000000..97d1013
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/InstallConfigurationModel.java
@@ -0,0 +1,327 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.model;
+
+import java.io.*;
+import java.net.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configurator.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.core.model.*;
+import org.eclipse.update.internal.core.*;
+
+/**
+ * An InstallConfigurationModel is
+ *
+ */
+
+public class InstallConfigurationModel extends ModelObject {
+
+ // performance
+ private URL bundleURL;
+ private URL base;
+ private boolean resolved = false;
+
+ private boolean isCurrent = false;
+ private URL locationURL;
+ private String locationURLString;
+ protected Date date;
+ private String label;
+ private List /* of ConfiguretionActivityModel */ activities;
+ private List /* of configurationSiteModel */ configurationSites;
+
+ protected boolean initialized = false;
+ protected boolean lightlyInitialized = false;
+
+ /**
+ * default constructor. Create
+ */
+ public InstallConfigurationModel() {
+ }
+
+ /**
+ * @since 2.0
+ */
+ public ConfiguredSiteModel[] getConfigurationSitesModel() {
+ if (!initialized)
+ initialize();
+ if (configurationSites == null || configurationSites.size() == 0)
+ return new ConfiguredSiteModel[0];
+
+ return (ConfiguredSiteModel[]) configurationSites.toArray(arrayTypeFor(configurationSites));
+ }
+
+ /**
+ * Adds the configuration to the list
+ * is called when adding a Site or parsing the XML file
+ * in this case we do not want to create a new activity, so we do not want t call
+ * addConfigurationSite()
+ */
+ public void addConfigurationSiteModel(ConfiguredSiteModel site) {
+ if (configurationSites == null) {
+ configurationSites = new ArrayList();
+ }
+ if (!configurationSites.contains(site)) {
+ configurationSites.add(site);
+ }
+ }
+
+ public void setConfigurationSiteModel(ConfiguredSiteModel[] sites) {
+ configurationSites = null;
+ for (int i = 0; i < sites.length; i++) {
+ addConfigurationSiteModel(sites[i]);
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ public boolean removeConfigurationSiteModel(ConfiguredSiteModel site) {
+ if (!initialized) initialize();
+
+ if (configurationSites != null) {
+ return configurationSites.remove(site);
+ }
+
+ return false;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public boolean isCurrent() {
+ if (!lightlyInitialized && !initialized )
+ doLightInitialization();
+
+ return isCurrent;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void setCurrent(boolean isCurrent) {
+ // do not check if writable as we may
+ // set an install config as Not current
+ this.isCurrent = isCurrent;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public ConfigurationActivityModel[] getActivityModel() {
+ if (activities == null && !initialized)
+ initialize();
+ if (activities == null || activities.size() == 0)
+ return new ConfigurationActivityModel[0];
+ return (ConfigurationActivityModel[]) activities.toArray(arrayTypeFor(activities));
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void addActivityModel(ConfigurationActivityModel activity) {
+ if (activities == null)
+ activities = new ArrayList();
+ if (!activities.contains(activity)) {
+ activities.add(activity);
+ activity.setInstallConfigurationModel(this);
+ }
+ }
+ /**
+ *
+ */
+ public Date getCreationDate() {
+// if (!initialized) initialize();
+ if (date == null)
+ doLightInitialization();
+ return date;
+ }
+ /**
+ * Sets the date.
+ * @param date The date to set
+ */
+ public void setCreationDate(Date date) {
+ assertIsWriteable();
+ this.date = date;
+ }
+ /**
+ * @since 2.0
+ */
+ public URL getURL() {
+ //if (!initialized) initialize();
+ //no need to initialize, always set
+ delayedResolve();
+ return locationURL;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public String getLabel() {
+// if (!initialized) initialize();
+ if (label == null)
+ doLightInitialization();
+ return label;
+ }
+
+ /**
+ * @since 2.0.2
+ */
+
+ public String toString() {
+ return getLabel();
+ }
+
+ /**
+ * Sets the label.
+ * @param label The label to set
+ */
+ public void setLabel(String label) {
+ assertIsWriteable();
+ this.label = label;
+ }
+
+ /**
+ * Gets the locationURLString.
+ * @return Returns a String
+ */
+ public String getLocationURLString() {
+ if (!initialized) delayedResolve();
+ return locationURLString;
+ }
+
+ /**
+ * Sets the locationURLString.
+ * @param locationURLString The locationURLString to set
+ */
+ public void setLocationURLString(String locationURLString) {
+ assertIsWriteable();
+ this.locationURLString = locationURLString;
+ this.locationURL = null;
+ }
+
+ /*
+ * @see ModelObject#resolve(URL, ResourceBundle)
+ */
+ public void resolve(URL base, URL bundleURL) throws MalformedURLException {
+
+ this.base = base;
+ this.bundleURL = bundleURL;
+
+ }
+
+ /**
+ * Returns the timeline.
+ * @return long
+ */
+ public long getTimeline() {
+ return 0;
+// if (!initialized) initialize();
+// return timeline;
+ }
+
+
+ /*
+ * initialize the configurations from the persistent model.
+ */
+ private void initialize() {
+
+ try {
+ try {
+ IPlatformConfiguration platformConfig = getPlatformConfiguration();
+
+ new InstallConfigurationParser(platformConfig, this, false);
+ } catch (FileNotFoundException exception) {
+ UpdateCore.warn(locationURLString + " does not exist, The local site is not in synch with the file system and is pointing to a file that doesn't exist.", exception); //$NON-NLS-1$
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallConfiguration_ErrorDuringFileAccess, (new String[] { locationURLString })), exception);
+ } catch (IOException exception) {
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallConfiguration_ErrorDuringFileAccess, (new String[] { locationURLString })), exception);
+ }
+
+ } catch (CoreException e) {
+ UpdateCore.warn("Error processing configuration history:" + locationURL.toExternalForm(), e); //$NON-NLS-1$
+ } finally {
+ initialized = true;
+ }
+
+ //finish resolve
+ // PERF:
+ try {
+ // delegate
+ resolveListReference(getActivityModel(), base, bundleURL);
+ resolveListReference(getConfigurationSitesModel(), base, bundleURL);
+ } catch (MalformedURLException e){}
+ }
+
+ private IPlatformConfiguration getPlatformConfiguration() throws IOException {
+ IPlatformConfiguration platformConfig;
+ if (UpdateManagerUtils.sameURL(getURL(), ConfiguratorUtils.getCurrentPlatformConfiguration().getConfigurationLocation()))
+ platformConfig = ConfiguratorUtils.getCurrentPlatformConfiguration();
+ else
+ platformConfig = ConfiguratorUtils.getPlatformConfiguration(getURL());
+ return platformConfig;
+ }
+
+ private void doLightInitialization() {
+ try {
+ try {
+ IPlatformConfiguration platformConfig = getPlatformConfiguration();
+
+ new InstallConfigurationParser(platformConfig, this, true);
+ } catch (FileNotFoundException exception) {
+ UpdateCore.warn(locationURLString + " does not exist, The local site is not in synch with the file system and is pointing to a file that doesn't exist.", exception); //$NON-NLS-1$
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallConfiguration_ErrorDuringFileAccess, (new String[] { locationURLString })), exception);
+ } catch (IOException exception) {
+ throw Utilities.newCoreException(NLS.bind(Messages.InstallConfiguration_ErrorDuringFileAccess, (new String[] { locationURLString })), exception);
+ }
+ } catch (CoreException e) {
+ UpdateCore.warn("Error processing configuration history:" + locationURL.toExternalForm(), e); //$NON-NLS-1$
+ } finally {
+ lightlyInitialized = true;
+ }
+ }
+
+ /*
+ *
+ */
+ private void delayedResolve() {
+
+ // PERF: delay resolution
+ if (resolved)
+ return;
+
+ resolved = true;
+ // resolve local elements
+ try {
+ //locationURL = resolveURL(base, bundleURL, locationURLString);
+ locationURL = new URL(locationURLString);
+ } catch (MalformedURLException e){
+ File f = new File(locationURLString);
+ try {
+ if (f.exists())
+ locationURL = f.toURL();
+ else
+ locationURL = base;
+ } catch (MalformedURLException e1) {
+ locationURL = base;
+ }
+ }
+ }
+
+ public void resetActivities() {
+ activities = null;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/InstallConfigurationParser.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/InstallConfigurationParser.java
new file mode 100644
index 0000000..b367bb0
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/InstallConfigurationParser.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.model;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Date;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.update.configurator.IPlatformConfiguration;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.SiteFeatureReference;
+import org.eclipse.update.core.SiteManager;
+import org.eclipse.update.core.model.SiteModel;
+import org.eclipse.update.internal.configurator.FeatureEntry;
+import org.eclipse.update.internal.configurator.PlatformConfiguration;
+import org.eclipse.update.internal.configurator.SiteEntry;
+import org.eclipse.update.internal.core.BaseSiteLocalFactory;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+
+
+/**
+ * parse the default site.xml
+ */
+
+public class InstallConfigurationParser {
+ private PlatformConfiguration platformConfig;
+ private URL siteURL;
+ private InstallConfigurationModel config;
+ private ConfiguredSiteModel configSite;
+
+ /**
+ * Constructor for DefaultSiteParser
+ */
+ public InstallConfigurationParser(
+ IPlatformConfiguration platformConfig,
+ InstallConfigurationModel config, boolean light)
+ throws IOException, CoreException {
+
+ Assert.isTrue(platformConfig instanceof PlatformConfiguration);
+ this.platformConfig = (PlatformConfiguration)platformConfig;
+
+ this.config = config;
+
+ // DEBUG:
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
+ UpdateCore.debug("Start parsing Configuration:" + (config).getURL().toExternalForm()); //$NON-NLS-1$
+ }
+
+ if (light) {
+ processConfigurationLight(this.platformConfig);
+ } else {
+ processConfig(this.platformConfig);
+ }
+ }
+
+
+
+
+
+ /**
+ * process the Site info
+ */
+ private void processSite(SiteEntry siteEntry) throws CoreException, IOException {
+
+ //site url
+ siteURL = siteEntry.getURL();
+ try {
+ siteURL = FileLocator.toFileURL(siteURL);
+ // TODO workaround bug in platform url resolution
+ if (siteURL.getProtocol().equals("file")) //$NON-NLS-1$
+ siteURL = new File(siteURL.getFile()).toURL();
+ } catch (IOException e) {
+ // keep original url
+ }
+
+ // policy
+ ISite site = SiteManager.getSite(siteURL,null);
+
+ // configuration site
+ BaseSiteLocalFactory factory = new BaseSiteLocalFactory();
+ configSite = factory.createConfigurationSiteModel((SiteModel) site, siteEntry.getSitePolicy().getType());
+
+ //platform url
+ configSite.setPlatformURLString(siteEntry.getURL().toExternalForm());
+
+ // configured
+ configSite.setEnabled(siteEntry.isEnabled());
+
+ // check if the site exists and is updatable
+ configSite.setUpdatable(siteEntry.isUpdateable());
+
+ // add to install configuration
+ config.addConfigurationSiteModel(configSite);
+ configSite.setInstallConfigurationModel(config);
+
+ FeatureEntry[] features = siteEntry.getFeatureEntries();
+ for (int i=0; i<features.length; i++) {
+ processFeature(features[i]);
+ }
+ }
+
+ /**
+ * process the DefaultFeature info
+ */
+ private void processFeature(FeatureEntry feature) throws CoreException, IOException {
+
+ // url
+ String path = feature.getURL();
+ URL url = UpdateManagerUtils.getURL(siteURL, path, null);
+
+ if (url != null) {
+ SiteFeatureReference ref = new SiteFeatureReference();
+ ref.setSite((ISite) configSite.getSiteModel());
+ ref.setURL(url);
+ (configSite.getConfigurationPolicyModel()).addConfiguredFeatureReference(ref);
+
+ //updateURL
+//TODO do we need the update url and to resolve it?
+// String updateURLString = attributes.getValue("updateURL"); //$NON-NLS-1$
+// URLEntry entry = new URLEntry();
+// entry.setURLString(updateURLString);
+// entry.resolve(siteURL,null);
+
+ // DEBUG:
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
+ UpdateCore.debug("End Processing DefaultFeature Tag: url:" + url.toExternalForm()); //$NON-NLS-1$
+ }
+
+ } else {
+ UpdateCore.log( Messages.InstallConfigurationParser_FeatureReferenceNoURL, new Exception());
+ }
+
+ }
+
+ /**
+ * process the Activity info
+ */
+// private void processActivity(Attributes attributes) {
+//
+// // action
+// String actionString = attributes.getValue("action"); //$NON-NLS-1$
+// int action = Integer.parseInt(actionString);
+//
+// // create
+// ConfigurationActivityModel activity =
+// new BaseSiteLocalFactory().createConfigurationActivityModel();
+// activity.setAction(action);
+//
+// // label
+// String label = attributes.getValue("label"); //$NON-NLS-1$
+// if (label != null)
+// activity.setLabel(label);
+//
+// // date
+// String dateString = attributes.getValue("date"); //$NON-NLS-1$
+// Date date = new Date(Long.parseLong(dateString));
+// activity.setDate(date);
+//
+// // status
+// String statusString = attributes.getValue("status"); //$NON-NLS-1$
+// int status = Integer.parseInt(statusString);
+// activity.setStatus(status);
+//
+// config.addActivityModel(activity);
+//
+// // DEBUG:
+// if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
+// UpdateCore.debug("End Processing Activity: action:" + actionString + " label: " + label + " date:" + dateString + " status" + statusString); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+// }
+//
+// }
+
+ /**
+ * process the Config info
+ */
+ private void processConfig(PlatformConfiguration platformConfig) throws IOException, CoreException {
+
+ // date
+ processConfigurationLight(platformConfig);
+
+ //timeline
+// String timelineString = attributes.getValue("timeline"); //$NON-NLS-1$
+// long timeline = config.getCreationDate().getTime();
+// if (timelineString!=null) {
+// timeline = Long.parseLong(timelineString);
+// }
+// config.setTimeline(timeline);
+
+ SiteEntry[] sites = platformConfig.getConfiguration().getSites();
+ for (int i=0; i<sites.length; i++)
+ processSite(sites[i]);
+
+ }
+
+
+
+ private void processConfigurationLight(PlatformConfiguration platformConfig) {
+ Date date = new Date(platformConfig.getChangeStamp());
+ config.setCreationDate(date);
+ config.setLabel(date.toString());
+
+ config.setCurrent( date.equals(org.eclipse.update.internal.configurator.PlatformConfiguration.getCurrent().getConfiguration().getDate()));
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/SiteLocalModel.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/SiteLocalModel.java
new file mode 100644
index 0000000..499d471
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/SiteLocalModel.java
@@ -0,0 +1,286 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.model;
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.MissingResourceException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.update.core.model.ModelObject;
+import org.eclipse.update.internal.core.BaseSiteLocalFactory;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+
+/**
+ * This class manages the configurations.
+ */
+
+public class SiteLocalModel extends ModelObject {
+ public static final String CONFIG_FILE = "platform.xml"; //$NON-NLS-1$
+ private long stamp;
+ private String label;
+ private URL location;
+ private String locationURLString;
+ private int history = UpdateCore.DEFAULT_HISTORY;
+ private List /* of InstallConfigurationModel */configurations;
+ private List /* of InstallConfigurationModel */preservedConfigurations;
+ private InstallConfigurationModel currentConfiguration;
+
+ /**
+ * Constructor for LocalSite
+ */
+ public SiteLocalModel(){
+ super();
+ }
+
+ /**
+ * @since 2.0
+ */
+ public InstallConfigurationModel getCurrentConfigurationModel() {
+ return currentConfiguration;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public InstallConfigurationModel[] getConfigurationHistoryModel() {
+ if (configurations==null)
+ // initialize history
+ processHistory();
+
+ if (configurations == null || configurations.size() == 0)
+ return new InstallConfigurationModel[0];
+ else
+ return (InstallConfigurationModel[])configurations.toArray(arrayTypeFor(configurations));
+ }
+
+ /**
+ * adds a new configuration to the LocalSite
+ * the newly added configuration is teh current one
+ */
+ public void addConfigurationModel(InstallConfigurationModel config) {
+ if (config != null) {
+ if (configurations == null)
+ configurations = new ArrayList();
+ if (!configurations.contains(config))
+ configurations.add(config);
+ }
+ }
+
+ /**
+ * adds a new configuration to the LocalSite
+ * the newly added configuration is teh current one
+ */
+ public boolean removeConfigurationModel(InstallConfigurationModel config) {
+ if (config != null) {
+ return configurations.remove(config);
+ }
+ return false;
+ }
+ /**
+ * Gets the location of the local site.
+ * @return Returns a URL
+ */
+ public URL getLocationURL() {
+ return location;
+ }
+
+ /**
+ * Gets the locationURLString.
+ * @return Returns a String
+ */
+ public String getLocationURLString() {
+ return locationURLString;
+ }
+
+
+ /**
+ * Sets the locationURLString.
+ * @param locationURLString The locationURLString to set
+ */
+ public void setLocationURLString(String locationURLString) {
+ assertIsWriteable();
+ this.locationURLString = locationURLString;
+ this.location=null;
+ }
+
+
+ /**
+ * @since 2.0
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Sets the label.
+ * @param label The label to set
+ */
+ public void setLabel(String label) {
+ assertIsWriteable();
+ this.label = label;
+ }
+
+
+ /**
+ * @since 2.0
+ */
+ public int getMaximumHistoryCount() {
+ return history;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void setMaximumHistoryCount(int history) {
+ assertIsWriteable();
+ this.history = history;
+ }
+
+
+ /**
+ * Adds a preserved configuration into teh collection
+ * do not save the configuration
+ * @since 2.0
+ */
+ public void addPreservedInstallConfigurationModel(InstallConfigurationModel configuration) {
+ if (preservedConfigurations == null)
+ preservedConfigurations = new ArrayList();
+
+ preservedConfigurations.add(configuration);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public boolean removePreservedConfigurationModel(InstallConfigurationModel configuration) {
+ if (preservedConfigurations != null) {
+ return preservedConfigurations.remove(configuration);
+ }
+ return false;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public InstallConfigurationModel[] getPreservedConfigurationsModel() {
+ if (preservedConfigurations==null || preservedConfigurations.isEmpty())
+ return new InstallConfigurationModel[0];
+ return (InstallConfigurationModel[])preservedConfigurations.toArray(arrayTypeFor(preservedConfigurations));
+ }
+
+
+ /**
+ * Sets the currentConfiguration.
+ * @param currentConfiguration The currentConfiguration to set
+ */
+ public void setCurrentConfigurationModel(InstallConfigurationModel currentConfiguration) {
+ assertIsWriteable();
+ this.currentConfiguration = currentConfiguration;
+
+ //2.0.2 set the configuredSite of sites
+ ConfiguredSiteModel[] confSites = currentConfiguration.getConfigurationSitesModel();
+ for (int i = 0; i < confSites.length; i++) {
+ confSites[i].getSiteModel().setConfiguredSiteModel(confSites[i]);
+ }
+ }
+
+ /*
+ * @see ModelObject#resolve(URL)
+ */
+ public void resolve(URL base,URL bundleURL) throws MalformedURLException {
+ // local
+ location = resolveURL(base,bundleURL,getLocationURLString());
+
+ // delegate
+ resolveListReference(getConfigurationHistoryModel(),base,bundleURL);
+ resolveListReference(getPreservedConfigurationsModel(),base,bundleURL);
+ resolveReference(getCurrentConfigurationModel(),base,bundleURL);
+ }
+
+
+ /**
+ * Gets the stamp.
+ * @return Returns a long
+ */
+ public long getStamp() {
+ return stamp;
+ }
+
+ /**
+ * Sets the stamp.
+ * @param stamp The stamp to set
+ */
+ public void setStamp(long stamp) {
+ this.stamp = stamp;
+ }
+
+ /**
+ * @see org.eclipse.update.core.model.ModelObject#getPropertyName()
+ */
+ protected String getPropertyName() {
+ return "platform"; //$NON-NLS-1$
+ }
+
+ /*
+ * reads the configuration/history directory
+ */
+ private void processHistory() {
+ try {
+ URL historyURL = new URL(getLocationURL(), "history"); //$NON-NLS-1$
+ historyURL = FileLocator.toFileURL(historyURL);
+ File historyDir = new File(historyURL.getFile());
+ if (historyDir.exists()) {
+ File[] backedConfigs = historyDir.listFiles();
+ BaseSiteLocalFactory factory = new BaseSiteLocalFactory();
+ for (int i=0; i<backedConfigs.length; i++) {
+ String name = backedConfigs[i].getName();
+ if (name.endsWith(".xml")) //$NON-NLS-1$
+ name = name.substring(0, name.length()-4);
+ else
+ continue;
+ Date date = new Date(Long.parseLong(name));
+ InstallConfigurationModel config = factory.createInstallConfigurationModel();
+ config.setLocationURLString(backedConfigs[i].getAbsolutePath().replace('\\', '/'));
+ config.setLabel(date.toString());
+ config.setCreationDate(date);
+ config.resolve(backedConfigs[i].toURL(), getResourceBundleURL());
+
+ // add the config
+ addConfigurationModel(config);
+ }
+ }
+ } catch (Exception e) {
+ UpdateCore.warn("Error processing history: ", e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * return the appropriate resource bundle for this sitelocal
+ */
+ URL getResourceBundleURL() throws CoreException {
+ URL url = null;
+ try {
+ url = UpdateManagerUtils.asDirectoryURL(getLocationURL());
+ } catch (MissingResourceException e) {
+ UpdateCore.warn(e.getLocalizedMessage() + ":" + url.toExternalForm()); //$NON-NLS-1$
+ } catch (MalformedURLException e) {
+ UpdateCore.warn(e.getLocalizedMessage());
+ }
+ return url;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/SiteLocalParser.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/SiteLocalParser.java
new file mode 100644
index 0000000..4b72663
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/SiteLocalParser.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.model;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.update.configuration.ILocalSite;
+import org.eclipse.update.configurator.IPlatformConfiguration;
+import org.eclipse.update.internal.configurator.PlatformConfiguration;
+import org.eclipse.update.internal.core.BaseSiteLocalFactory;
+import org.eclipse.update.internal.core.InstallConfiguration;
+import org.eclipse.update.internal.core.LocalSite;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+
+/**
+ * parse the default site.xml
+ */
+
+public class SiteLocalParser {
+
+ private PlatformConfiguration platformConfig;
+ private SiteLocalModel site;
+ public static final String CONFIG = "config"; //$NON-NLS-1$
+ private ResourceBundle bundle;
+ private BaseSiteLocalFactory factory = new BaseSiteLocalFactory();
+
+ /**
+ * return the appropriate resource bundle for this sitelocal
+ */
+ private ResourceBundle getResourceBundle() throws CoreException {
+ ResourceBundle bundle = null;
+ URL url = null;
+ try {
+ url = UpdateManagerUtils.asDirectoryURL(site.getLocationURL());
+ ClassLoader l = new URLClassLoader(new URL[] { url }, null);
+ bundle = ResourceBundle.getBundle("platform", Locale.getDefault(), l); //$NON-NLS-1$
+ } catch (MissingResourceException e) {
+ UpdateCore.warn(e.getLocalizedMessage() + ":" + url.toExternalForm()); //$NON-NLS-1$
+ } catch (MalformedURLException e) {
+ UpdateCore.warn(e.getLocalizedMessage());
+ }
+ return bundle;
+ }
+
+ /**
+ * Constructor for DefaultSiteParser
+ */
+ public SiteLocalParser(IPlatformConfiguration platformConfig, ILocalSite site) throws IOException, CoreException {
+ Assert.isTrue(platformConfig instanceof PlatformConfiguration);
+ this.platformConfig = (PlatformConfiguration)platformConfig;
+
+ Assert.isTrue(site instanceof SiteLocalModel);
+ this.site = (SiteLocalModel) site;
+
+ // DEBUG:
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
+ UpdateCore.debug("Start parsing localsite:" + ((SiteLocalModel) site).getLocationURLString()); //$NON-NLS-1$
+ }
+
+ bundle = getResourceBundle();
+
+ processConfig();
+ //processHistory();
+ }
+
+
+// /**
+// * process the Site info
+// */
+// private void processSite(Attributes attributes) throws MalformedURLException {
+// //
+// String info = attributes.getValue("label"); //$NON-NLS-1$
+// info = UpdateManagerUtils.getResourceString(info, bundle);
+// site.setLabel(info);
+//
+// // history
+// String historyString = attributes.getValue("history"); //$NON-NLS-1$
+// int history;
+// if (historyString == null || historyString.equals("")) { //$NON-NLS-1$
+// history = SiteLocalModel.DEFAULT_HISTORY;
+// } else {
+// history = Integer.parseInt(historyString);
+// }
+// site.setMaximumHistoryCount(history);
+//
+// //stamp
+// String stampString = attributes.getValue("stamp"); //$NON-NLS-1$
+// long stamp = Long.parseLong(stampString);
+// site.setStamp(stamp);
+//
+// // DEBUG:
+// if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
+// UpdateCore.debug("End process Site label:" + info); //$NON-NLS-1$
+// }
+//
+// }
+
+ /**
+ * process the Config info
+ */
+ private void processConfig() throws MalformedURLException, CoreException {
+
+ String label = platformConfig.getConfiguration().getDate().toString();
+ label = UpdateManagerUtils.getResourceString(label, bundle);
+ site.setLabel(label);
+
+ URL url = site.getLocationURL();
+ InstallConfigurationModel config = factory.createInstallConfigurationModel();
+ config.setLocationURLString(url.toExternalForm());
+ config.setLabel(label);
+ config.resolve(url, site.getResourceBundleURL());
+
+ // add the config
+ ((LocalSite)site).addConfiguration((InstallConfiguration)config);
+
+ // DEBUG:
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
+ UpdateCore.debug("End Processing Config Tag: url:" + url.toExternalForm()); //$NON-NLS-1$
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/SiteWithTimestamp.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/SiteWithTimestamp.java
new file mode 100644
index 0000000..a74d323
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/model/SiteWithTimestamp.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.model;
+
+import java.util.Date;
+
+import org.eclipse.update.core.Site;
+
+/**
+ * This is a wrapper class for Site class that adds timestamp
+ *
+ *
+ */
+public class SiteWithTimestamp extends Site implements ITimestamp {
+
+ private Date timestamp;
+
+ /*private Site site;
+
+ public SiteWithTimestamp( Site site) {
+ this.site = site;
+ }*/
+
+ public Date getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(Date timestamp) {
+ this.timestamp = timestamp;
+
+ }
+/*
+ public boolean isReadOnly() {
+ return site.isReadOnly();
+ }
+
+ public Object getAdapter(Class adapter) {
+ return site.getAdapter(adapter);
+ }
+
+ public void addPluginEntry(IPluginEntry pluginEntry) {
+ site.addPluginEntry(pluginEntry);
+ }
+
+ public IFeature createFeature(String type, URL url) throws CoreException {
+ return site.createFeature(type, url);
+ }
+
+ public IFeature createFeature(String type, URL url, IProgressMonitor monitor) throws CoreException {
+ return site.createFeature(type, url, monitor);
+ }
+
+ public IArchiveReference[] getArchives() {
+ return site.getArchives();
+ }
+
+ public ICategory[] getCategories() {
+ return site.getCategories();
+ }
+
+ public ICategory getCategory(String key) {
+ return site.getCategory(key);
+ }
+
+ public IConfiguredSite getCurrentConfiguredSite() {
+ return site.getCurrentConfiguredSite();
+ }
+
+ public String getDefaultPackagedFeatureType() {
+ return site.getDefaultPackagedFeatureType();
+ }
+
+ public IURLEntry getDescription() {
+ return site.getDescription();
+ }
+
+ public long getDownloadSizeFor(IFeature feature) {
+ return site.getDownloadSizeFor(feature);
+ }
+
+ public ISiteFeatureReference getFeatureReference(IFeature feature) {
+ return site.getFeatureReference(feature);
+ }
+
+ public ISiteFeatureReference[] getFeatureReferences() {
+ return site.getFeatureReferences();
+ }
+
+ public long getInstallSizeFor(IFeature feature) {
+ return site.getInstallSizeFor(feature);
+ }
+
+ public IURLEntry[] getMirrorSiteEntries() {
+ return site.getMirrorSiteEntries();
+ }
+
+ public IPluginEntry[] getPluginEntries() {
+ return site.getPluginEntries();
+ }
+
+ public IPluginEntry[] getPluginEntriesOnlyReferencedBy(IFeature feature) throws CoreException {
+ return site.getPluginEntriesOnlyReferencedBy(feature);
+ }
+
+ public int getPluginEntryCount() {
+ return site.getPluginEntryCount();
+ }
+
+ public ISiteFeatureReference[] getRawFeatureReferences() {
+ return site.getRawFeatureReferences();
+ }
+
+ public ISiteContentProvider getSiteContentProvider() throws CoreException {
+ return site.getSiteContentProvider();
+ }
+
+ public URL getURL() {
+ return site.getURL();
+ }
+
+ public IFeatureReference install(IFeature sourceFeature, IFeatureReference[] optionalFeatures, IFeatureContentConsumer parentContentConsumer, IVerifier parentVerifier, IVerificationListener verificationListener, IProgressMonitor progress) throws CoreException {
+ return site.install(sourceFeature, optionalFeatures, parentContentConsumer,
+ parentVerifier, verificationListener, progress);
+ }
+
+ public IFeatureReference install(IFeature sourceFeature, IFeatureReference[] optionalFeatures, IVerificationListener verificationListener, IProgressMonitor progress) throws InstallAbortedException, CoreException {
+ return site.install(sourceFeature, optionalFeatures, verificationListener,
+ progress);
+ }
+
+ public IFeatureReference install(IFeature sourceFeature, IVerificationListener verificationListener, IProgressMonitor progress) throws InstallAbortedException, CoreException {
+ return site.install(sourceFeature, verificationListener, progress);
+ }
+
+ public void remove(IFeature feature, IProgressMonitor progress) throws CoreException {
+ site.remove(feature, progress);
+ }
+
+ public void setSiteContentProvider(ISiteContentProvider siteContentProvider) {
+ site.setSiteContentProvider(siteContentProvider);
+ }
+
+ public void addArchiveReferenceModel(ArchiveReferenceModel archiveReference) {
+ site.addArchiveReferenceModel(archiveReference);
+ }
+
+ public void addCategoryModel(CategoryModel category) {
+ site.addCategoryModel(category);
+ }
+
+ public void addFeatureReferenceModel(SiteFeatureReferenceModel featureReference) {
+ site.addFeatureReferenceModel(featureReference);
+ }
+
+ public void addMirrorModel(URLEntryModel mirror) {
+ site.addMirrorModel(mirror);
+ }
+
+ public ArchiveReferenceModel[] getArchiveReferenceModels() {
+ return site.getArchiveReferenceModels();
+ }
+
+ public CategoryModel[] getCategoryModels() {
+ return site.getCategoryModels();
+ }
+
+ public ConfiguredSiteModel getConfiguredSiteModel() {
+ return site.getConfiguredSiteModel();
+ }
+
+ public URLEntryModel getDescriptionModel() {
+ return site.getDescriptionModel();
+ }
+
+ public SiteFeatureReferenceModel[] getFeatureReferenceModels() {
+ return site.getFeatureReferenceModels();
+ }
+
+ public URL getLocationURL() {
+ return site.getLocationURL();
+ }
+
+ public String getLocationURLString() {
+ return site.getLocationURLString();
+ }
+
+ public URLEntryModel[] getMirrorSiteEntryModels() {
+ return site.getMirrorSiteEntryModels();
+ }
+
+ public String getType() {
+ return site.getType();
+ }
+
+ public void markReadOnly() {
+ site.markReadOnly();
+ }
+
+ public void removeArchiveReferenceModel(ArchiveReferenceModel archiveReference) {
+ site.removeArchiveReferenceModel(archiveReference);
+ }
+
+ public void removeCategoryModel(CategoryModel category) {
+ site.removeCategoryModel(category);
+ }
+
+ public void removeFeatureReferenceModel(FeatureReferenceModel featureReference) {
+ site.removeFeatureReferenceModel(featureReference);
+ }
+
+ public void removeMirror(URLEntryModel mirror) {
+ site.removeMirror(mirror);
+ }
+
+ public void resolve(URL base, URL bundleURL) throws MalformedURLException {
+ site.resolve(base, bundleURL);
+ }
+
+ public void setArchiveReferenceModels(ArchiveReferenceModel[] archiveReferences) {
+ site.setArchiveReferenceModels(archiveReferences);
+ }
+
+ public void setCategoryModels(CategoryModel[] categories) {
+ site.setCategoryModels(categories);
+ }
+
+ public void setConfiguredSiteModel(ConfiguredSiteModel configuredSiteModel) {
+ site.setConfiguredSiteModel(configuredSiteModel);
+ }
+
+ public void setDescriptionModel(URLEntryModel description) {
+ site.setDescriptionModel(description);
+ }
+
+ public void setFeatureReferenceModels(FeatureReferenceModel[] featureReferences) {
+ site.setFeatureReferenceModels(featureReferences);
+ }
+
+ public void setLocationURLString(String locationURLString) {
+ site.setLocationURLString(locationURLString);
+ }
+
+ public void setMirrorSiteEntryModels(URLEntryModel[] mirrors) {
+ site.setMirrorSiteEntryModels(mirrors);
+ }
+
+ public void setMirrorsURLString(String mirrorsURL) {
+ site.setMirrorsURLString(mirrorsURL);
+ }
+
+ public void setType(String type) {
+ site.setType(type);
+ }
+*/
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/BatchFeatureOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/BatchFeatureOperation.java
new file mode 100644
index 0000000..cf8436f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/BatchFeatureOperation.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.update.internal.operations;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.operations.IOperation;
+import org.eclipse.update.operations.IOperationListener;
+
+public abstract class BatchFeatureOperation extends Operation implements IBatchFeatureOperation {
+
+ private IFeature[] features;
+ private IConfiguredSite[] targetSites;
+
+
+ public BatchFeatureOperation(IConfiguredSite[] targetSites, IFeature[] features) {
+ super();
+ this.features = features;
+ this.targetSites = targetSites;
+ }
+
+ public IFeature[] getFeatures() {
+ return features;
+ }
+
+ public IConfiguredSite[] getTargetSites() {
+ return targetSites;
+ }
+
+ public void setTargetSites(IConfiguredSite[] targetSites) {
+ this.targetSites = targetSites;
+
+ }
+
+ public boolean execute(IProgressMonitor pm, IOperationListener listener)
+ throws CoreException, InvocationTargetException {
+
+ if (getFeatures() == null || getFeatures().length == 0)
+ return false;
+ IOperation[] operations = new IOperation[getFeatures().length];
+
+ for ( int i = 0; i < getFeatures().length; i ++) {
+ operations[i] = createOperation(getTargetSites()[i], getFeatures()[i]);
+ }
+
+ boolean restartNeeded = false;
+
+ for ( int i = 0; i < operations.length; i ++) {
+ try {
+ boolean status = operations[i].execute(pm, listener);
+ if (status)
+ restartNeeded = true;
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+ return restartNeeded;
+
+ }
+
+ protected abstract IOperation createOperation(IConfiguredSite targetSite, IFeature feature);
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/BatchInstallOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/BatchInstallOperation.java
new file mode 100644
index 0000000..d524d2d
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/BatchInstallOperation.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 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.update.internal.operations;
+
+import java.lang.reflect.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.core.model.*;
+import org.eclipse.update.internal.core.*;
+import org.eclipse.update.operations.*;
+
+public class BatchInstallOperation
+ extends Operation
+ implements IBatchOperation {
+
+ protected IInstallFeatureOperation[] operations;
+
+ public BatchInstallOperation(IInstallFeatureOperation[] operations) {
+ super();
+ this.operations = operations;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.operations.IMultiOperation#getOperations()
+ */
+ public IFeatureOperation[] getOperations() {
+ return operations;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.operations.IOperation#execute(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public boolean execute(IProgressMonitor monitor, IOperationListener listener) throws CoreException, InvocationTargetException {
+ int installCount = 0;
+
+ if (operations == null || operations.length == 0)
+ return false;
+
+ IStatus status = OperationsManager.getValidator().validatePendingChanges(operations);
+ if (status != null && status.getCode() == IStatus.ERROR) {
+ throw new CoreException(status);
+ }
+
+// // Check for duplication conflicts
+// ArrayList conflicts =
+// DuplicateConflictsValidator.computeDuplicateConflicts(
+// operations,
+// config);
+// if (conflicts != null) {
+// boolean continueProcessing = false;
+// if (listener != null)
+// continueProcessing = listener.beforeExecute(this, conflicts);
+// if (!continueProcessing)
+// return false;
+// }
+
+ OperationsManager.setInProgress(true);
+ if (monitor == null)
+ monitor = new NullProgressMonitor();
+
+ try {
+ if (listener != null)
+ listener.beforeExecute(this, null);
+
+ monitor.beginTask(
+ Messages.OperationsManager_installing,
+ operations.length);
+ for (int i = 0; i < operations.length; i++) {
+ SubProgressMonitor subMonitor =
+ new SubProgressMonitor(
+ monitor,
+ 1,
+ SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
+
+ operations[i].execute(subMonitor, listener);
+ OperationsManager.addPendingOperation(operations[i]);
+
+ operations[i].markProcessed();
+ if (listener != null)
+ listener.afterExecute(operations[i], null);
+
+ //monitor.worked(1);
+ installCount++;
+ }
+ return SiteManager.getLocalSite().save();
+ } catch (InstallAbortedException e) {
+ // saves the current configuration
+ if (installCount > 0) {
+ try {
+ SiteManager.getLocalSite().save();
+ } catch (CoreException ce) {
+ UpdateUtils.logException(ce);
+ }
+ }
+ throw new InvocationTargetException(e);
+ } catch (CoreException e) {
+ // saves the current configuration
+ if (installCount > 0) {
+ try {
+ SiteManager.getLocalSite().save();
+ } catch (CoreException ce) {
+ UpdateUtils.logException(ce);
+ }
+ }
+ throw new InvocationTargetException(e);
+ } finally {
+ OperationsManager.setInProgress(false);
+ monitor.done();
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/ConfigOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/ConfigOperation.java
new file mode 100644
index 0000000..3bb18c0
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/ConfigOperation.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 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.update.internal.operations;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.operations.*;
+
+/**
+ * Configure a feature.
+ * ConfigOperation
+ */
+public class ConfigOperation
+extends FeatureOperation
+implements IConfigFeatureOperation {
+
+ public ConfigOperation(
+ IConfiguredSite site,
+ IFeature feature) {
+ super(site, feature);
+ }
+
+ public boolean execute(IProgressMonitor pm, IOperationListener listener)
+ throws CoreException {
+
+ IStatus status =
+ OperationsManager.getValidator().validatePendingConfig(feature);
+ if (status != null && status.getCode() == IStatus.ERROR) {
+ throw new CoreException(status);
+ }
+ try {
+ targetSite.configure(feature);
+ //ensureUnique();
+
+ // Restart not needed
+ boolean restartNeeded = false;
+
+ // Check if this operation is cancelling one that's already pending
+ IOperation pendingOperation =
+ OperationsManager.findPendingOperation(feature);
+
+ if (pendingOperation instanceof IUnconfigFeatureOperation) {
+ // no need to do either pending change
+ OperationsManager.removePendingOperation(pendingOperation);
+ } else {
+ OperationsManager.addPendingOperation(this);
+ }
+
+ markProcessed();
+ if (listener != null)
+ listener.afterExecute(this, null);
+
+ restartNeeded = SiteManager.getLocalSite().save() && restartNeeded;
+
+ // notify the model
+ OperationsManager.fireObjectChanged(feature, null);
+
+ return restartNeeded;
+ } catch (CoreException e) {
+ undo();
+ UpdateUtils.logException(e);
+ throw e;
+ }
+ }
+
+ public void undo() throws CoreException {
+ targetSite.unconfigure(feature);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/ConfigureFeaturesOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/ConfigureFeaturesOperation.java
new file mode 100644
index 0000000..3247973
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/ConfigureFeaturesOperation.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.update.internal.operations;
+
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.operations.IOperation;
+import org.eclipse.update.operations.OperationsManager;
+
+public class ConfigureFeaturesOperation extends BatchFeatureOperation implements
+ IConfigureFeaturesOperation {
+
+ public ConfigureFeaturesOperation(IConfiguredSite[] targetSites,
+ IFeature[] features) {
+ super(targetSites, features);
+ }
+
+
+ protected IOperation createOperation(IConfiguredSite targetSite, IFeature feature) {
+ return OperationsManager.getOperationFactory().createConfigOperation(targetSite, feature);
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/DuplicateConflictsValidator.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/DuplicateConflictsValidator.java
new file mode 100644
index 0000000..dda495e
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/DuplicateConflictsValidator.java
@@ -0,0 +1,225 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.operations;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.configuration.IInstallConfiguration;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IFeatureReference;
+import org.eclipse.update.core.IIncludedFeatureReference;
+import org.eclipse.update.core.VersionedIdentifier;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.operations.IInstallFeatureOperation;
+
+
+/**
+ *
+ */
+public class DuplicateConflictsValidator {
+
+ public static class IdEntry {
+ IConfiguredSite csite;
+ IFeature feature;
+
+ public IdEntry(IFeature feature, IConfiguredSite csite) {
+ this.feature = feature;
+ this.csite = csite;
+ if (csite == null) {
+ System.out.println("csite null"); //$NON-NLS-1$
+ }
+ }
+ public boolean isInstallCandidate() {
+ return csite != null;
+ }
+ public IFeature getFeature() {
+ return feature;
+ }
+
+ public String getIdentifier() {
+ return feature.getVersionedIdentifier().getIdentifier();
+ }
+ public IConfiguredSite getConfiguredSite() {
+ if (csite != null)
+ return csite;
+ return feature.getSite().getCurrentConfiguredSite();
+ }
+ public boolean sameLevel(IdEntry entry) {
+ VersionedIdentifier vid = feature.getVersionedIdentifier();
+ VersionedIdentifier evid =
+ entry.getFeature().getVersionedIdentifier();
+ return vid.equals(evid);
+ }
+ public String toString() {
+ IConfiguredSite configSite = getConfiguredSite();
+ String version =
+ feature.getVersionedIdentifier().getVersion().toString();
+ String location = configSite.getSite().getURL().getFile();
+ return NLS.bind(Messages.DuplicateConflictsDialog_conflict, (new String[] { version, location }));
+ }
+ }
+
+ public static ArrayList computeDuplicateConflicts(
+ IInstallFeatureOperation job,
+ IInstallConfiguration config,
+ IConfiguredSite targetSite,
+ IFeatureReference[] optionalFeatures) {
+ Hashtable featureTable = new Hashtable();
+ try {
+ computePresentState(featureTable, config);
+ computeNewFeature(
+ job.getFeature(),
+ targetSite,
+ featureTable,
+ optionalFeatures);
+ return computeConflicts(featureTable);
+ } catch (CoreException e) {
+ return null;
+ }
+ }
+
+ public static ArrayList computeDuplicateConflicts(
+ IInstallFeatureOperation[] jobs,
+ IInstallConfiguration config) {
+ Hashtable featureTable = new Hashtable();
+ computePresentState(featureTable, config);
+ computeNewFeatures(jobs, featureTable);
+ return computeConflicts(featureTable);
+ }
+
+ private static ArrayList computeConflicts(Hashtable featureTable) {
+ ArrayList result = null;
+ for (Enumeration iterator = featureTable.elements();
+ iterator.hasMoreElements();
+ ) {
+ ArrayList candidate = (ArrayList) iterator.nextElement();
+ if (candidate.size() == 1)
+ continue;
+ ArrayList conflict = checkForConflict(candidate);
+ if (conflict != null) {
+ if (result == null)
+ result = new ArrayList();
+ result.add(conflict);
+ }
+ }
+ return result;
+ }
+
+ private static ArrayList checkForConflict(ArrayList candidate) {
+ IdEntry firstEntry = null;
+ for (int i = 0; i < candidate.size(); i++) {
+ IdEntry entry = (IdEntry) candidate.get(i);
+ if (firstEntry == null)
+ firstEntry = entry;
+ else if (!entry.sameLevel(firstEntry))
+ return candidate;
+ }
+ return null;
+ }
+
+ private static void computePresentState(
+ Hashtable table,
+ IInstallConfiguration config) {
+ IConfiguredSite[] csites = config.getConfiguredSites();
+ for (int i = 0; i < csites.length; i++) {
+ IConfiguredSite csite = csites[i];
+ IFeatureReference[] refs = csite.getConfiguredFeatures();
+ for (int j = 0; j < refs.length; j++) {
+ try {
+ addEntry(refs[j].getFeature(null), csite, table);
+ } catch (CoreException e) {
+ // don't let one bad feature stop the loop
+ }
+ }
+ }
+ }
+
+ private static void computeNewFeatures(
+ IInstallFeatureOperation[] jobs,
+ Hashtable featureTable) {
+ for (int i = 0; i < jobs.length; i++) {
+ IInstallFeatureOperation job = jobs[i];
+ IConfiguredSite targetSite = job.getTargetSite();
+ IFeature newFeature = job.getFeature();
+ try {
+ computeNewFeature(newFeature, targetSite, featureTable, null);
+ } catch (CoreException e) {
+ }
+ }
+ }
+
+ private static void computeNewFeature(
+ IFeature feature,
+ IConfiguredSite csite,
+ Hashtable table,
+ IFeatureReference[] optionalFeatures)
+ throws CoreException {
+ addEntry(feature, csite, table);
+ IIncludedFeatureReference[] irefs =
+ feature.getIncludedFeatureReferences();
+ for (int i = 0; i < irefs.length; i++) {
+ IIncludedFeatureReference iref = irefs[i];
+ boolean add = true;
+
+ if (iref.isOptional() && optionalFeatures != null) {
+ boolean found = false;
+ for (int j = 0; j < optionalFeatures.length; j++) {
+ IFeatureReference checked = optionalFeatures[j];
+ if (checked.equals(iref)) {
+ found = true;
+ break;
+ }
+ }
+ add = found;
+ }
+ if (add)
+ computeNewFeature(
+ iref.getFeature(null),
+ csite,
+ table,
+ optionalFeatures);
+ }
+ }
+
+ private static void addEntry(
+ IFeature feature,
+ IConfiguredSite csite,
+ Hashtable featureTable) {
+ String id = feature.getVersionedIdentifier().getIdentifier();
+ ArrayList entries = (ArrayList) featureTable.get(id);
+ if (entries == null) {
+ entries = new ArrayList();
+ featureTable.put(id, entries);
+ }
+ IdEntry entry = new IdEntry(feature, csite);
+ boolean replaced = false;
+ for (int i = 0; i < entries.size(); i++) {
+ IdEntry existingEntry = (IdEntry) entries.get(i);
+ IConfiguredSite existingSite = existingEntry.getConfiguredSite();
+ if (existingSite.equals(entry.getConfiguredSite())) {
+ // same site - replace it if not new
+ if (entry.isInstallCandidate()) {
+ entries.set(i, entry);
+ entries.remove(existingEntry);
+ }
+ replaced = true;
+ break;
+ }
+ }
+ if (!replaced)
+ entries.add(entry);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/FeatureHierarchyElement.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/FeatureHierarchyElement.java
new file mode 100644
index 0000000..1e71d39
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/FeatureHierarchyElement.java
@@ -0,0 +1,446 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.operations;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.*;
+
+/**
+ * This class is used to construct a joint feature hiearchy.
+ * Old feature reference represents feature that is
+ * found on in the current configuration. New feature
+ * reference is found in the feature that is an install/update
+ * candidate. The element is used to join nodes of the
+ * hiearchy formed by including features so that
+ * each node in the hiearchy contains references to the
+ * old and the new feature. Old and new features have
+ * the same IDs but different versions, except in
+ * the case of optional features, where the tree may
+ * be constructed to bring in an optional feature
+ * that was not installed initially. In that case,
+ * some nodes may have old an new references with the
+ * same ID and version.
+ * <p>
+ * Old feature reference may be null. That means
+ * that the older feature with the same ID but lower
+ * version was not found in the current configuration.
+ */
+public class FeatureHierarchyElement {
+
+ private Object root;
+ private ArrayList children;
+ private IFeatureReference oldFeatureRef;
+ private IFeatureReference newFeatureRef;
+ private boolean checked;
+ private boolean optionalChildren;
+ private boolean nativeUpgrade = false;
+
+ public FeatureHierarchyElement(
+ IFeatureReference oldRef,
+ IFeatureReference newRef) {
+ oldFeatureRef = oldRef;
+ newFeatureRef = newRef;
+ }
+
+ public void setRoot(Object root) {
+ this.root = root;
+ }
+
+ public Object getRoot() {
+ return root;
+ }
+
+ /*
+ * Return true if element can be checked, false otherwise.
+ */
+ public boolean isEditable() {
+ // cannot uncheck non-optional features
+ if (isOptional() == false)
+ return false;
+ // cannot uncheck optional feature that
+ // has already been installed
+ if (oldFeatureRef != null)
+ return false;
+ return true;
+ }
+
+ /**
+ * A hirearchy node represents a 'false update' if
+ * both old and new references exist and both
+ * point to the feature with the same ID and version.
+ * These nodes will not any bytes to be downloaded -
+ * they simply exist to allow the hirarchy to
+ * reach the optional children that are missing
+ * and will be installed.
+ */
+
+ public boolean isFalseUpdate() {
+ if (oldFeatureRef != null && newFeatureRef != null) {
+ try {
+ return oldFeatureRef.getVersionedIdentifier().equals(
+ newFeatureRef.getVersionedIdentifier());
+ } catch (CoreException e) {
+ }
+ }
+ return false;
+ }
+ /**
+ * Returns true if feature is included as optional.
+ */
+ public boolean isOptional() {
+ return newFeatureRef instanceof IIncludedFeatureReference
+ && ((IIncludedFeatureReference) newFeatureRef).isOptional();
+ }
+ /**
+ * Returns true if this optional feature is selected
+ * for installation. Non-optional features or non-editable
+ * features are always checked.
+ */
+ public boolean isChecked() {
+ return checked;
+ }
+
+ void setNativeUpgrade(boolean nativeUpgrade) {
+ this.nativeUpgrade = nativeUpgrade;
+ }
+
+ /**
+ * Returns true if this optional feature should
+ * be enabled when installed. By default, all
+ * features in the hiearchy should be enabled.
+ * The exception is for optional features that
+ * are updated to a new version in case where
+ * the older version of the optional feature
+ * is disabled in the given configuration.
+ * In this case, the feature is
+ * updated and disabled in order to maintain
+ * its state.
+ */
+ public boolean isEnabled(IInstallConfiguration config) {
+ if (nativeUpgrade)
+ return true;
+ if (isOptional() && oldFeatureRef != null) {
+ try {
+ IFeature oldFeature = oldFeatureRef.getFeature(null);
+ IConfiguredSite csite =
+ UpdateUtils.getConfigSite(oldFeature, config);
+ return csite.isConfigured(oldFeature);
+ } catch (CoreException e) {
+ }
+ }
+ return true;
+ }
+
+ public IFeature getFeature() {
+ try {
+ IFeature feature = newFeatureRef.getFeature(null);
+ return feature;
+ } catch (CoreException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Selects an editable feature for installation.
+ */
+ public void setChecked(boolean checked) {
+ this.checked = checked;
+ }
+ /**
+ * Returns label for UI presentation.
+ */
+ public String getLabel() {
+ try {
+ return getFeatureLabel(newFeatureRef);
+ } catch (CoreException e) {
+ if (newFeatureRef instanceof IIncludedFeatureReference) {
+ String iname =
+ ((IIncludedFeatureReference) newFeatureRef).getName();
+ if (iname != null)
+ return iname;
+ }
+ try {
+ VersionedIdentifier vid =
+ newFeatureRef.getVersionedIdentifier();
+ return vid.toString();
+ } catch (CoreException e2) {
+ }
+ }
+ return null;
+ }
+ /**
+ * Computes label from the feature.
+ */
+ private String getFeatureLabel(IFeatureReference featureRef)
+ throws CoreException {
+ IFeature feature = featureRef.getFeature(null);
+ return feature.getLabel()
+ + " " //$NON-NLS-1$
+ + feature.getVersionedIdentifier().getVersion().toString();
+ }
+ /**
+ * Computes children by linking matching features from the
+ * old feature's and new feature's hierarchy.
+ */
+ public FeatureHierarchyElement[] getChildren(
+ boolean update,
+ boolean patch,
+ IInstallConfiguration config) {
+ computeChildren(update, patch, config);
+ FeatureHierarchyElement[] array =
+ new FeatureHierarchyElement[children.size()];
+ children.toArray(array);
+ return array;
+ }
+
+ public FeatureHierarchyElement[] getChildren() {
+ if (children != null) {
+ FeatureHierarchyElement[] array =
+ new FeatureHierarchyElement[children.size()];
+ children.toArray(array);
+ return array;
+ }
+
+ return new FeatureHierarchyElement[0];
+ }
+ /**
+ * Computes children of this node.
+ */
+ public void computeChildren(
+ boolean update,
+ boolean patch,
+ IInstallConfiguration config) {
+ if (children == null) {
+ children = new ArrayList();
+ try {
+ IFeature oldFeature = null;
+ IFeature newFeature = null;
+ newFeature = newFeatureRef.getFeature(null);
+ if (oldFeatureRef != null)
+ oldFeature = oldFeatureRef.getFeature(null);
+ optionalChildren =
+ computeElements(
+ oldFeature,
+ newFeature,
+ update,
+ patch,
+ config,
+ children);
+ for (int i = 0; i < children.size(); i++) {
+ FeatureHierarchyElement element =
+ (FeatureHierarchyElement) children.get(i);
+ element.setRoot(getRoot());
+ }
+ } catch (CoreException e) {
+ }
+ }
+ }
+ /**
+ *
+ */
+ public boolean hasOptionalChildren() {
+ return optionalChildren;
+ }
+ /**
+ * Adds checked optional features to the provided set.
+ */
+ public void addCheckedOptionalFeatures(
+ boolean update,
+ boolean patch,
+ IInstallConfiguration config,
+ Set set) {
+ if (isOptional() && isChecked()) {
+ // Do not add checked optional features
+ // if this is an update case but
+ // the node is not a 'true' update
+ // (old and new feature are the equal)
+ if (!update || !isFalseUpdate())
+ set.add(newFeatureRef);
+ }
+ FeatureHierarchyElement[] elements = getChildren(update, patch, config);
+ for (int i = 0; i < elements.length; i++) {
+ elements[i].addCheckedOptionalFeatures(update, patch, config, set);
+ }
+ }
+
+ /**
+ * Computes first-level children of the linked hierarchy
+ * for the provided old and new features (same ID, different version
+ * where new version is greater or equal the old version).
+ * Old feature may be null.
+ */
+ public static boolean computeElements(
+ IFeature oldFeature,
+ IFeature newFeature,
+ boolean update,
+ boolean patch,
+ IInstallConfiguration config,
+ ArrayList list) {
+ Object[] oldChildren = null;
+ Object[] newChildren = getIncludedFeatures(newFeature);
+ boolean optionalChildren = false;
+
+ try {
+ if (oldFeature != null) {
+ oldChildren = getIncludedFeatures(oldFeature);
+ }
+ for (int i = 0; i < newChildren.length; i++) {
+ IFeatureReference oldRef = null;
+ IFeatureReference newRef = (IFeatureReference) newChildren[i];
+ if (oldChildren != null) {
+ String newId =
+ newRef.getVersionedIdentifier().getIdentifier();
+
+ for (int j = 0; j < oldChildren.length; j++) {
+ IFeatureReference cref =
+ (IFeatureReference) oldChildren[j];
+ try {
+ if (cref
+ .getVersionedIdentifier()
+ .getIdentifier()
+ .equals(newId)) {
+ oldRef = cref;
+ break;
+ }
+ } catch (CoreException ex) {
+ }
+ }
+ } else if (patch) {
+ // 30849 - find the old reference in the
+ // configuration.
+ if (!UpdateUtils.isPatch(newFeature)) {
+ oldRef = findPatchedReference(newRef, config);
+ }
+ }
+ // test if the old optional feature exists
+ if (oldRef != null
+ && ((oldRef instanceof IIncludedFeatureReference
+ && ((IIncludedFeatureReference) oldRef).isOptional())
+ || patch)) {
+ try {
+ IFeature f = oldRef.getFeature(null);
+ if (f == null)
+ oldRef = null;
+ } catch (CoreException e) {
+ // missing
+ oldRef = null;
+ }
+ }
+ FeatureHierarchyElement element =
+ new FeatureHierarchyElement(oldRef, newRef);
+ // If this is an update (old feature exists),
+ // only check the new optional feature if the old exists.
+ // Otherwise, always check.
+ if (element.isOptional() && (update || patch)) {
+ element.setChecked(oldRef != null);
+ if (oldRef == null) {
+ // Does not have an old reference,
+ // but it may contain an older
+ // feature that may still qualify
+ // for update. For example,
+ // an older version may have been
+ // installed natively from the CD-ROM.
+ if (hasOlderVersion(newRef)) {
+ element.setNativeUpgrade(true);
+ element.setChecked(true);
+ }
+ }
+ } else
+ element.setChecked(true);
+ list.add(element);
+ element.computeChildren(update, patch, config);
+ if (element.isOptional() || element.hasOptionalChildren())
+ optionalChildren = true;
+ }
+ } catch (CoreException e) {
+ }
+ return optionalChildren;
+ }
+ public static boolean hasOlderVersion(IFeatureReference newRef) {
+ try {
+ VersionedIdentifier vid = newRef.getVersionedIdentifier();
+ PluginVersionIdentifier version = vid.getVersion();
+ String mode = getUpdateVersionsMode();
+
+ IFeature[] allInstalled =
+ UpdateUtils.getInstalledFeatures(vid, false);
+ for (int i = 0; i < allInstalled.length; i++) {
+ IFeature candidate = allInstalled[i];
+ PluginVersionIdentifier cversion =
+ candidate.getVersionedIdentifier().getVersion();
+ // Verify that the difference qualifies as
+ // an update.
+ if (mode.equals(UpdateCore.EQUIVALENT_VALUE)) {
+ if (version.isEquivalentTo(cversion))
+ return true;
+ } else if (mode.equals(UpdateCore.COMPATIBLE_VALUE)) {
+ if (version.isCompatibleWith(cversion))
+ return true;
+ }
+ }
+ } catch (CoreException e) {
+ }
+ return false;
+ }
+
+ private static IFeatureReference findPatchedReference(
+ IFeatureReference newRef,
+ IInstallConfiguration config)
+ throws CoreException {
+ VersionedIdentifier vid = newRef.getVersionedIdentifier();
+ IConfiguredSite[] csites = config.getConfiguredSites();
+ for (int i = 0; i < csites.length; i++) {
+ IConfiguredSite csite = csites[i];
+ IFeatureReference[] refs = csite.getConfiguredFeatures();
+ for (int j = 0; j < refs.length; j++) {
+ IFeatureReference ref = refs[j];
+ VersionedIdentifier refVid = ref.getVersionedIdentifier();
+ if (vid.getIdentifier().equals(refVid.getIdentifier()))
+ return ref;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns included feature references for the given reference.
+ */
+ public static Object[] getIncludedFeatures(IFeatureReference ref) {
+ try {
+ IFeature feature = ref.getFeature(null);
+ return getIncludedFeatures(feature);
+ } catch (CoreException e) {
+ }
+ return new Object[0];
+ }
+
+ /**
+ * Returns included feature references for the given feature.
+ */
+
+ public static Object[] getIncludedFeatures(IFeature feature) {
+ try {
+ return feature.getIncludedFeatureReferences();
+ } catch (CoreException e) {
+ }
+ return new Object[0];
+ }
+
+ private static String getUpdateVersionsMode() {
+ Preferences store = UpdateCore.getPlugin().getPluginPreferences();
+ return store.getString(UpdateCore.P_UPDATE_VERSIONS);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/FeatureOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/FeatureOperation.java
new file mode 100644
index 0000000..dd7f988
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/FeatureOperation.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.operations;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.operations.*;
+
+
+public abstract class FeatureOperation extends Operation implements IFeatureOperation {
+
+ protected IFeature feature;
+ protected IFeature oldFeature;
+ protected IConfiguredSite targetSite;
+
+// private boolean optionalDelta;
+
+
+ public FeatureOperation(IConfiguredSite targetSite, IFeature feature) {
+ super();
+ this.feature = feature;
+ this.targetSite = targetSite;
+ }
+
+ public IFeature getFeature() {
+ return feature;
+ }
+
+ public IFeature getOldFeature() {
+ return oldFeature;
+ }
+
+// public boolean isOptionalDelta() {
+// return optionalDelta;
+// }
+
+ public IConfiguredSite getTargetSite() {
+ return targetSite;
+ }
+
+ public void setTargetSite(IConfiguredSite targetSite) {
+ this.targetSite = targetSite;
+ }
+
+
+ static boolean unconfigure(IFeature feature, IConfiguredSite site)
+ throws CoreException {
+ IInstallConfiguration config = SiteManager.getLocalSite().getCurrentConfiguration();
+ if (site == null)
+ site = UpdateUtils.getConfigSite(feature, config);
+
+ if (site != null) {
+ PatchCleaner cleaner = new PatchCleaner(site, feature);
+ boolean result = site.unconfigure(feature);
+ cleaner.dispose();
+ return result;
+ }
+ return false;
+ }
+
+ public void setFeature(IFeature feature) {
+ this.feature = feature;
+ }
+
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/FeatureStatus.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/FeatureStatus.java
new file mode 100644
index 0000000..982ed53
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/FeatureStatus.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.operations;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+
+
+/**
+ * The feature status provide info about the broken features and what is
+ * wrong.
+ */
+public class FeatureStatus extends Status {
+ public final static int CODE_OTHER = IStatus.OK;//0
+ public final static int CODE_PREREQ_FEATURE = 1;
+ public final static int CODE_PREREQ_PLUGIN = 2;
+ public final static int CODE_EXCLUSIVE = 4;
+ public final static int CODE_CYCLE = 8;
+ public final static int CODE_OPTIONAL_CHILD = 16;
+ public final static int CODE_ENVIRONMENT = 32;
+ IFeature feature;
+
+ public FeatureStatus(IFeature feature, int severity, String pluginId, int code, String message, Throwable exception) {
+ super(severity, pluginId, code, message, exception);
+ this.feature = feature;
+ }
+ public IFeature getFeature() {
+ return feature;
+ }
+ public boolean equals(Object obj) {
+ if (!(obj instanceof FeatureStatus))
+ return false;
+ FeatureStatus fs = (FeatureStatus) obj;
+ // only check for feature, regardless of status type
+ if (fs.getFeature() == feature)
+ return true;
+ else if (fs.getFeature() == null && feature == null)
+ return fs.getMessage().equals(getMessage());
+ else if (fs.getFeature() == null && feature != null)
+ return false;
+ else if (fs.getFeature() != null && feature == null)
+ return false;
+ else if (fs.getFeature().equals(feature))
+ return true;
+ else
+ return false;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IBatchFeatureOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IBatchFeatureOperation.java
new file mode 100644
index 0000000..75d7ada
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IBatchFeatureOperation.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.update.internal.operations;
+
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.operations.IOperation;
+
+public interface IBatchFeatureOperation extends IOperation {
+
+ /**
+ * Returns the features to operate on.
+ * @return the features to operate on.
+ */
+ public abstract IFeature[] getFeatures();
+ /**
+ * Returns the site in which the operation is applied.
+ * @return the site that owns or will own the feature.
+ */
+ public abstract IConfiguredSite[] getTargetSites();
+
+ /**
+ * Sets the site in which the feature is being operated on.
+ * @param targetSite the site in which the featre is being operated on.
+ */
+ public abstract void setTargetSites(IConfiguredSite[] targetSite);
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IConfigureFeaturesOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IConfigureFeaturesOperation.java
new file mode 100644
index 0000000..b1c3534
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IConfigureFeaturesOperation.java
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.update.internal.operations;
+
+public interface IConfigureFeaturesOperation extends IBatchFeatureOperation {
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IUnconfigureAndUninstallFeatureOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IUnconfigureAndUninstallFeatureOperation.java
new file mode 100644
index 0000000..ce5006d
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IUnconfigureAndUninstallFeatureOperation.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.update.internal.operations;
+
+import org.eclipse.update.operations.IFeatureOperation;
+
+public interface IUnconfigureAndUninstallFeatureOperation extends
+ IFeatureOperation {
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IUnconfigureAndUninstallFeaturesOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IUnconfigureAndUninstallFeaturesOperation.java
new file mode 100644
index 0000000..de9216f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IUnconfigureAndUninstallFeaturesOperation.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.update.internal.operations;
+
+public interface IUnconfigureAndUninstallFeaturesOperation extends
+ IBatchFeatureOperation {
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IUnconfigureFeaturesOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IUnconfigureFeaturesOperation.java
new file mode 100644
index 0000000..bdf5d5d
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IUnconfigureFeaturesOperation.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.update.internal.operations;
+
+
+public interface IUnconfigureFeaturesOperation extends IBatchFeatureOperation {
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IUninstallFeaturesOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IUninstallFeaturesOperation.java
new file mode 100644
index 0000000..46e6117
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/IUninstallFeaturesOperation.java
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.update.internal.operations;
+
+public interface IUninstallFeaturesOperation extends IBatchFeatureOperation {
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/InstallOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/InstallOperation.java
new file mode 100644
index 0000000..a282a70
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/InstallOperation.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.operations;
+
+import java.util.HashSet;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.operations.*;
+
+/**
+ * Configure a feature.
+ * ConfigOperation
+ */
+public class InstallOperation
+ extends FeatureOperation
+ implements IInstallFeatureOperation {
+
+ public boolean equals(Object arg) {
+ if (arg == null) {
+ return false;
+ }
+
+ if (!(arg instanceof InstallOperation)) {
+ return false;
+ }
+
+ InstallOperation io = (InstallOperation)arg;
+
+ return io.getFeature().getVersionedIdentifier().equals(this.getFeature().getVersionedIdentifier());
+ }
+
+ public int hashCode() {
+ // TODO Auto-generated method stub
+ return super.getFeature().hashCode();
+ }
+
+ private IFeatureReference[] optionalFeatures;
+ private IFeature[] unconfiguredOptionalFeatures;
+ private IVerificationListener verifier;
+
+ /**
+ * Constructor
+ * @param site
+ * @param feature
+ * @param optionalFeatures optional features to install. If null, the operation will install them all (if any)
+ * @param unconfiguredOptionalElements optional features unconfigured before the operation. They should remain unconfigured after the install.
+ * @param verifier
+ */
+ public InstallOperation(
+ IConfiguredSite site,
+ IFeature feature,
+ IFeatureReference[] optionalFeatures,
+ IFeature[] unconfiguredOptionalElements,
+ IVerificationListener verifier) {
+ super(site, feature);
+ IFeature[] installed = UpdateUtils.getInstalledFeatures(feature);
+ if (installed.length > 0)
+ this.oldFeature = installed[0];
+ this.unconfiguredOptionalFeatures = unconfiguredOptionalElements;
+ this.optionalFeatures = optionalFeatures;
+ this.verifier = verifier;
+ }
+
+ public IFeatureReference[] getOptionalFeatures() {
+ return optionalFeatures;
+ }
+
+ public boolean execute(IProgressMonitor pm, IOperationListener listener)
+ throws CoreException {
+
+ boolean reinstall = false;
+ if (oldFeature != null
+ && feature.getVersionedIdentifier().equals(
+ oldFeature.getVersionedIdentifier()))
+ reinstall = true;
+
+ setOptionalFeatures();
+
+ if (optionalFeatures == null)
+ targetSite.install(feature, verifier, pm);
+ else
+ targetSite.install(feature, optionalFeatures, verifier, pm);
+
+ if (!reinstall) {
+
+ if (oldFeature != null) { //&& isOptionalDelta()) {
+ preserveOptionalState();
+
+ boolean oldSuccess = unconfigure(oldFeature, null); // pick any site containing old feature
+ if (!oldSuccess) {
+ IInstallConfiguration config = SiteManager.getLocalSite().getCurrentConfiguration();
+ if (!UpdateUtils.isNestedChild(config, oldFeature)) {
+ // "eat" the error if nested child
+ String message =
+ NLS.bind(Messages.OperationsManager_error_old, (new String[] { oldFeature.getLabel() }));
+ IStatus status =
+ new Status(
+ IStatus.ERROR,
+ UpdateUtils.getPluginId(),
+ IStatus.OK,
+ message,
+ null);
+ throw new CoreException(status);
+ }
+ }
+ }
+
+// if (oldFeature == null) {
+// ensureUnique();
+// }
+ }
+ return true;
+ }
+
+ private void preserveOptionalState() {
+ if (unconfiguredOptionalFeatures == null)
+ return;
+
+ for (int i = 0; i < unconfiguredOptionalFeatures.length; i++) {
+ try {
+ // Get the feature that matches the original unconfigured ones.
+ IFeature localFeature =
+ UpdateUtils.getLocalFeature(
+ targetSite,
+ unconfiguredOptionalFeatures[i]);
+ if (localFeature != null)
+ targetSite.unconfigure(localFeature);
+
+ } catch (CoreException e) {
+ // Ignore this - we will leave with it
+ }
+ }
+ }
+
+ private void setOptionalFeatures() {
+ try {
+ // Ensure optional features are correctly set
+ if (optionalFeatures == null && UpdateUtils.hasOptionalFeatures(feature) ) {
+ JobRoot jobRoot = new JobRoot(this);
+ IInstallConfiguration config = SiteManager.getLocalSite().getCurrentConfiguration();
+ HashSet set = new HashSet();
+ boolean update = oldFeature != null;
+ boolean patch = UpdateUtils.isPatch(feature);
+ FeatureHierarchyElement[] elements = jobRoot.getElements();
+ for (int i = 0; i < elements.length; i++) {
+ elements[i].addCheckedOptionalFeatures(update, patch, config, set);
+ }
+ optionalFeatures = new IFeatureReference[set.size()];
+ set.toArray(optionalFeatures);
+ unconfiguredOptionalFeatures = jobRoot.getUnconfiguredOptionalFeatures(config, targetSite);
+ }
+ } catch (CoreException e) {
+ UpdateUtils.logException(e);
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/JobRoot.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/JobRoot.java
new file mode 100644
index 0000000..bc4a535
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/JobRoot.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.operations;
+
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.operations.*;
+
+public class JobRoot {
+ private IInstallFeatureOperation job;
+ private FeatureHierarchyElement[] elements;
+
+ public JobRoot(IInstallFeatureOperation job) {
+ this.job = job;
+ }
+
+ public IInstallFeatureOperation getJob() {
+ return job;
+ }
+
+ public FeatureHierarchyElement[] getElements() {
+ if (elements == null)
+ computeElements();
+ return elements;
+ }
+
+ /**
+ * Returns unconfigured features before an install.
+ * After installing the features, the caller must get the local features that match
+ * these unconfigured features and unconfigure them.
+ * @param config
+ * @param targetSite
+ * @return
+ */
+ public IFeature[] getUnconfiguredOptionalFeatures(
+ IInstallConfiguration config,
+ IConfiguredSite targetSite) {
+
+ ArrayList unconfiguredOptionalFeatures = new ArrayList();
+ getUnconfiguredOptionalFeatures(unconfiguredOptionalFeatures, config, targetSite, getElements(), UpdateUtils.isPatch(job.getFeature()));
+ IFeature[] unconfiguredOptionalFeaturesArray =
+ new IFeature[unconfiguredOptionalFeatures.size()];
+ unconfiguredOptionalFeatures.toArray(unconfiguredOptionalFeaturesArray);
+ return unconfiguredOptionalFeaturesArray;
+ }
+
+ private void getUnconfiguredOptionalFeatures(
+ ArrayList unconfiguredOptionalFeatures,
+ IInstallConfiguration config,
+ IConfiguredSite targetSite,
+ FeatureHierarchyElement[] optionalElements,
+ boolean isPatch) {
+ for (int i = 0; i < optionalElements.length; i++) {
+ FeatureHierarchyElement[] children =
+ optionalElements[i].getChildren(true, isPatch, config);
+ getUnconfiguredOptionalFeatures(
+ unconfiguredOptionalFeatures,
+ config,
+ targetSite,
+ children,
+ isPatch);
+ if (!optionalElements[i].isEnabled(config)) {
+ unconfiguredOptionalFeatures.add(optionalElements[i].getFeature());
+ }
+ }
+ }
+
+ private void computeElements() {
+ try {
+ IFeature oldFeature = job.getOldFeature();
+ IFeature newFeature = job.getFeature();
+ ArrayList list = new ArrayList();
+ boolean patch = UpdateUtils.isPatch(newFeature);
+ FeatureHierarchyElement.computeElements(
+ oldFeature,
+ newFeature,
+ oldFeature != null,
+ patch,
+ SiteManager.getLocalSite().getCurrentConfiguration(),
+ list);
+ elements = new FeatureHierarchyElement[list.size()];
+ list.toArray(elements);
+ for (int i = 0; i < elements.length; i++) {
+ elements[i].setRoot(this);
+ }
+ } catch (CoreException e) {
+ UpdateUtils.logException(e);
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/Operation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/Operation.java
new file mode 100644
index 0000000..5250bb2
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/Operation.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.operations;
+
+import org.eclipse.update.operations.*;
+
+
+public abstract class Operation implements IOperation {
+
+ private boolean processed;
+
+
+ public Operation() {
+ }
+
+ public boolean isProcessed() {
+ return processed;
+ }
+
+ public void markProcessed() {
+ processed = true;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/OperationFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/OperationFactory.java
new file mode 100644
index 0000000..636f376
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/OperationFactory.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.operations;
+
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.operations.*;
+
+public class OperationFactory implements IOperationFactory {
+
+ public OperationFactory() {
+ }
+
+ public IConfigFeatureOperation createConfigOperation(
+ IConfiguredSite targetSite,
+ IFeature feature) {
+ return new ConfigOperation(targetSite, feature);
+ }
+
+ public IBatchOperation createBatchInstallOperation(IInstallFeatureOperation[] operations) {
+ return new BatchInstallOperation(operations);
+ }
+
+ public IInstallFeatureOperation createInstallOperation(
+ IConfiguredSite targetSite,
+ IFeature feature,
+ IFeatureReference[] optionalFeatures,
+ IFeature[] unconfiguredOptionalFeatures,
+ IVerificationListener verifier) {
+ return new InstallOperation(
+ targetSite,
+ feature,
+ optionalFeatures,
+ unconfiguredOptionalFeatures,
+ verifier);
+ }
+
+ public IUnconfigFeatureOperation createUnconfigOperation(
+ IConfiguredSite targetSite,
+ IFeature feature) {
+ return new UnconfigOperation(targetSite, feature);
+ }
+
+ public IConfigFeatureOperation createReplaceFeatureVersionOperation(
+ IFeature feature,
+ IFeature anotherFeature) {
+
+ return new ReplaceFeatureVersionOperation(feature, anotherFeature);
+ }
+
+ public IUninstallFeatureOperation createUninstallOperation(
+ IConfiguredSite targetSite,
+ IFeature feature) {
+ return new UninstallOperation(targetSite, feature);
+ }
+
+ public IRevertConfigurationOperation createRevertConfigurationOperation(
+ IInstallConfiguration config,
+ IProblemHandler problemHandler) {
+ return new RevertConfigurationOperation(
+ config,
+ problemHandler);
+ }
+
+ public IToggleSiteOperation createToggleSiteOperation(
+ IConfiguredSite site) {
+ return new ToggleSiteOperation(site);
+ }
+
+ public IUnconfigureAndUninstallFeatureOperation createUnconfigureAndUninstallFeatureOperation(
+ IConfiguredSite targetSite,
+ IFeature feature) {
+ return new UnconfigureAndUninstallFeatureOperation(targetSite, feature);
+ }
+
+ public IUnconfigureFeaturesOperation createUnconfigureFeaturesOperation (
+ IConfiguredSite[] targetSites,
+ IFeature[] features) {
+ return new UnconfigureFeaturesOperation(targetSites, features);
+ }
+
+ public IConfigureFeaturesOperation createConfigureFeaturesOperation(
+ IConfiguredSite[] targetSites,
+ IFeature[] features) {
+
+ return new ConfigureFeaturesOperation(targetSites, features);
+ }
+
+ public IUninstallFeaturesOperation createUninstallFeaturesOperation(
+ IConfiguredSite[] targetSites,
+ IFeature[] features) {
+ return new UninstallFeaturesOperation(targetSites, features);
+ }
+
+ public IUnconfigureAndUninstallFeaturesOperation createUnconfigureAndUninstallFeaturesOperation(
+ IConfiguredSite[] targetSites,
+ IFeature[] features) {
+ return new UnconfigureAndUninstallFeaturesOperation(targetSites, features);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/OperationValidator.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/OperationValidator.java
new file mode 100644
index 0000000..03af25b
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/OperationValidator.java
@@ -0,0 +1,1397 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.operations;
+
+//import java.io.*;
+//import java.net.*;
+//import java.nio.channels.*;
+import org.eclipse.update.core.IUpdateConstants;
+
+import org.eclipse.osgi.service.resolver.PlatformAdmin;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.service.resolver.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.configurator.ConfiguratorUtils;
+import org.eclipse.update.configurator.IPlatformConfiguration;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.configurator.PlatformConfiguration;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.operations.IInstallFeatureOperation;
+import org.eclipse.update.operations.IOperationValidator;
+import org.osgi.framework.*;
+
+/**
+ *
+ */
+public class OperationValidator implements IOperationValidator {
+ /**
+ * Checks if the platform configuration has been modified outside this program.
+ * @return the error status, or null if no errors
+ */
+ public IStatus validatePlatformConfigValid() {
+ ArrayList status = new ArrayList(1);
+ checkPlatformWasModified(status);
+
+ // report status
+ if (status.size() > 0)
+ return createMultiStatus(Messages.ActivityConstraints_rootMessage, status, IStatus.ERROR);
+ return null;
+ }
+
+ /*
+ * Called by UI before performing operation. Returns null if no errors, a
+ * status with IStatus.WARNING code when the initial configuration is
+ * broken, or a status with IStatus.ERROR when there the operation
+ * introduces new errors
+ */
+ public IStatus validatePendingInstall(
+ IFeature oldFeature,
+ IFeature newFeature) {
+ // check initial state
+ ArrayList beforeStatus = new ArrayList();
+ validateInitialState(beforeStatus);
+
+ // check proposed change
+ ArrayList status = new ArrayList();
+ checkPlatformWasModified(status);
+ validateInstall(oldFeature, newFeature, status);
+
+ // report status
+ return createCombinedReportStatus(beforeStatus, status);
+ }
+
+ /*
+ * Called by UI before performing operation
+ */
+ public IStatus validatePendingUnconfig(IFeature feature) {
+ // check initial state
+ ArrayList beforeStatus = new ArrayList();
+ validateInitialState(beforeStatus);
+
+ // check proposed change
+ ArrayList status = new ArrayList();
+ checkPlatformWasModified(status);
+ validateUnconfigure(feature, status);
+
+ // report status
+ return createCombinedReportStatus(beforeStatus, status);
+ }
+
+ /*
+ * Called by UI before performing operation
+ */
+ public IStatus validatePendingConfig(IFeature feature) {
+ // check initial state
+ ArrayList beforeStatus = new ArrayList();
+ validateInitialState(beforeStatus);
+
+ // check proposed change
+ ArrayList status = new ArrayList();
+ checkPlatformWasModified(status);
+ validateConfigure(feature, status);
+
+ // report status
+ return createCombinedReportStatus(beforeStatus, status);
+ }
+
+ /**
+ * Called before performing operation.
+ */
+ public IStatus validatePendingReplaceVersion(
+ IFeature feature,
+ IFeature anotherFeature) {
+ // check initial state
+ ArrayList beforeStatus = new ArrayList();
+ validateInitialState(beforeStatus);
+
+ // check proposed change
+ ArrayList status = new ArrayList();
+ checkPlatformWasModified(status);
+ validateReplaceVersion(feature, anotherFeature, status);
+
+ // report status
+ return createCombinedReportStatus(beforeStatus, status);
+ }
+
+
+ /*
+ * Called by the UI before doing a revert/ restore operation
+ */
+ public IStatus validatePendingRevert(IInstallConfiguration config) {
+ // check initial state
+ ArrayList beforeStatus = new ArrayList();
+ validateInitialState(beforeStatus);
+
+ // check proposed change
+ ArrayList status = new ArrayList();
+ checkPlatformWasModified(status);
+ validateRevert(config, status);
+
+ // report status
+ return createCombinedReportStatus(beforeStatus, status);
+ }
+
+ /*
+ * Called by the UI before doing a batched processing of several pending
+ * changes.
+ */
+ public IStatus validatePendingChanges(IInstallFeatureOperation[] jobs) {
+ // check initial state
+ ArrayList beforeStatus = new ArrayList();
+ validateInitialState(beforeStatus);
+ checkPlatformWasModified(beforeStatus);
+
+ // check proposed change
+ ArrayList status = new ArrayList();
+ validatePendingChanges(jobs, status, beforeStatus);
+
+ // report status
+ return createCombinedReportStatus(beforeStatus, status);
+ }
+
+ /*
+ * Called by the UI before doing a batched processing of several pending
+ * changes.
+ */
+ public RequiredFeaturesResult getRequiredFeatures(IInstallFeatureOperation[] jobs) {
+
+ RequiredFeaturesResult requiredFeaturesResult = new RequiredFeaturesResult();
+ // check initial state
+ ArrayList beforeStatus = new ArrayList();
+ validateInitialState(beforeStatus);
+ checkPlatformWasModified(beforeStatus);
+
+ // check proposed change
+ ArrayList status = new ArrayList();
+ Set requiredFeatures = validatePendingChanges(jobs, status, beforeStatus);
+
+ // report status
+ //return createCombinedReportStatus(beforeStatus, status);
+ requiredFeaturesResult.setRequiredFeatures(requiredFeatures);
+ requiredFeaturesResult.setStatus(createCombinedReportStatus(beforeStatus, status));
+ return requiredFeaturesResult;
+ }
+
+ /*
+ * Check the current state.
+ */
+ public IStatus validateCurrentState() {
+ // check the state
+ ArrayList status = new ArrayList();
+ checkPlatformWasModified(status);
+ validateInitialState(status);
+
+ // report status
+ if (status.size() > 0)
+ return createMultiStatus(Messages.ActivityConstraints_rootMessage, status, IStatus.ERROR);
+ return null;
+ }
+
+ /*
+ * Check to see if we are not broken even before we start
+ */
+ private static void validateInitialState(ArrayList status) {
+ try {
+ ArrayList features = computeFeatures();
+ // uncomment this when patch released in boot
+ //checkConfigurationLock(status);
+ checkConstraints(features, status);
+ } catch (CoreException e) {
+ status.add(e.getStatus());
+ }
+ }
+
+ /*
+ * handle unconfigure
+ */
+ private static void validateUnconfigure(
+ IFeature feature,
+ ArrayList status) {
+ try {
+ checkSiteReadOnly(feature,status);
+ ArrayList features = computeFeatures();
+ features = computeFeaturesAfterOperation(features, null, feature);
+ checkConstraints(features, status);
+ } catch (CoreException e) {
+ status.add(e.getStatus());
+ }
+ }
+
+
+ /*
+ * handle configure
+ */
+ private static void validateConfigure(IFeature feature, ArrayList status) {
+ try {
+ checkSiteReadOnly(feature,status);
+ ArrayList features = computeFeatures();
+ checkOptionalChildConfiguring(feature, status);
+ checkForCycles(feature, null, features);
+ features = computeFeaturesAfterOperation(features, feature, null);
+ checkConstraints(features, status);
+
+ } catch (CoreException e) {
+ status.add(e.getStatus());
+ }
+ }
+
+ /*
+ * handle replace version
+ */
+ private static void validateReplaceVersion(
+ IFeature feature,
+ IFeature anotherFeature,
+ ArrayList status) {
+ try {
+ checkSiteReadOnly(feature,status);
+ ArrayList features = computeFeatures();
+ checkForCycles(feature, null, features);
+ features =
+ computeFeaturesAfterOperation(
+ features,
+ anotherFeature,
+ feature);
+ checkConstraints(features, status);
+ } catch (CoreException e) {
+ status.add(e.getStatus());
+ }
+ }
+
+ /*
+ * handle install and update
+ */
+ private static void validateInstall(
+ IFeature oldFeature,
+ IFeature newFeature,
+ ArrayList status) {
+ try {
+ checkSiteReadOnly(oldFeature,status);
+ ArrayList features = computeFeatures();
+ checkForCycles(newFeature, null, features);
+ features =
+ computeFeaturesAfterOperation(features, newFeature, oldFeature);
+ checkConstraints(features, status);
+ checkLicense(newFeature, status);
+ } catch (CoreException e) {
+ status.add(e.getStatus());
+ }
+ }
+
+ /*
+ * handle revert and restore
+ */
+ private static void validateRevert(
+ IInstallConfiguration config,
+ ArrayList status) {
+ try {
+// // check the timeline and don't bother
+// // to check anything else if negative
+// if (!checkTimeline(config, status))
+// return;
+ ArrayList features = computeFeaturesAfterRevert(config);
+ checkConstraints(features, status);
+ checkRevertConstraints(features, status);
+
+ } catch (CoreException e) {
+ status.add(e.getStatus());
+ }
+ }
+
+
+ /*
+ * Handle one-click changes as a batch
+ */
+ private static Set validatePendingChanges(
+ IInstallFeatureOperation[] jobs,
+ ArrayList status,
+ ArrayList beforeStatus) {
+ try {
+ ArrayList features = computeFeatures();
+ ArrayList savedFeatures = features;
+ int nexclusives = 0;
+
+ // pass 1: see if we can process the entire "batch"
+ ArrayList tmpStatus = new ArrayList();
+ for (int i = 0; i < jobs.length; i++) {
+ IInstallFeatureOperation job = jobs[i];
+
+ IFeature newFeature = job.getFeature();
+ IFeature oldFeature = job.getOldFeature();
+ checkLicense(newFeature, status);
+ if (jobs.length > 1 && newFeature.isExclusive()) {
+ nexclusives++;
+ status.add(
+ createStatus(
+ newFeature,
+ FeatureStatus.CODE_EXCLUSIVE,
+ Messages.ActivityConstraints_exclusive));
+ continue;
+ }
+ checkForCycles(newFeature, null, features);
+ features =
+ computeFeaturesAfterOperation(
+ features,
+ newFeature,
+ oldFeature);
+ }
+ if (nexclusives > 0)
+ return Collections.EMPTY_SET;
+ checkConstraints(features, tmpStatus);
+ if (tmpStatus.size() == 0) // the whole "batch" is OK
+ return Collections.EMPTY_SET;
+
+ // pass 2: we have conflicts
+ features = savedFeatures;
+ for (int i = 0; i < jobs.length; i++) {
+ IInstallFeatureOperation job = jobs[i];
+ IFeature newFeature = job.getFeature();
+ IFeature oldFeature = job.getOldFeature();
+
+ features =
+ computeFeaturesAfterOperation(
+ features,
+ newFeature,
+ oldFeature);
+
+ Set result = checkConstraints(features, status);
+ if (status.size() > 0
+ && !isBetterStatus(beforeStatus, status)) {
+// bug 75613
+// IStatus conflict =
+// createStatus(
+// newFeature,
+// FeatureStatus.CODE_OTHER,
+// Policy.bind(KEY_CONFLICT));
+// status.add(0, conflict);
+ return result;
+ }
+ }
+ } catch (CoreException e) {
+ status.add(e.getStatus());
+ }
+
+ return Collections.EMPTY_SET;
+ }
+
+ private static void checkPlatformWasModified(ArrayList status) {
+ try {
+ // checks if the platform has been modified outside this eclipse instance
+ IPlatformConfiguration platformConfig = ConfiguratorUtils.getCurrentPlatformConfiguration();
+
+ long currentTimeStamp = platformConfig.getChangeStamp();
+ // get the last modified value for this config, from this process point of view
+ if (platformConfig instanceof PlatformConfiguration)
+ currentTimeStamp = ((PlatformConfiguration)platformConfig).getConfiguration().lastModified();
+
+ // get the real last modified value
+ URL platformXML = platformConfig.getConfigurationLocation();
+ long actualTimeStamp = currentTimeStamp;
+ if ("file".equals(platformXML.getProtocol())) //$NON-NLS-1$
+ actualTimeStamp = new File(platformXML.getFile()).lastModified();
+ else {
+ URLConnection connection = platformXML.openConnection();
+ actualTimeStamp = connection.getLastModified();
+ }
+ if (currentTimeStamp != actualTimeStamp)
+ status.add(createStatus(
+ null,
+ FeatureStatus.CODE_OTHER,
+ Messages.ActivityConstraints_platformModified));
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+
+ private static void checkSiteReadOnly(IFeature feature, ArrayList status) {
+ if(feature == null){
+ return;
+ }
+ IConfiguredSite csite = feature.getSite().getCurrentConfiguredSite();
+ if (csite != null && !csite.isUpdatable())
+ status.add(createStatus(feature, FeatureStatus.CODE_OTHER,
+ NLS.bind(Messages.ActivityConstraints_readOnly, (new String[] { csite.getSite().getURL().toExternalForm() }))));
+ }
+
+ /*
+ * Compute a list of configured features
+ */
+ private static ArrayList computeFeatures() throws CoreException {
+ return computeFeatures(true);
+ }
+ /*
+ * Compute a list of configured features
+ */
+ private static ArrayList computeFeatures(boolean configuredOnly)
+ throws CoreException {
+ ArrayList features = new ArrayList();
+ ILocalSite localSite = SiteManager.getLocalSite();
+ IInstallConfiguration config = localSite.getCurrentConfiguration();
+ IConfiguredSite[] csites = config.getConfiguredSites();
+
+ for (int i = 0; i < csites.length; i++) {
+ IConfiguredSite csite = csites[i];
+
+ IFeatureReference[] crefs;
+
+ if (configuredOnly)
+ crefs = csite.getConfiguredFeatures();
+ else
+ crefs = csite.getSite().getFeatureReferences();
+ for (int j = 0; j < crefs.length; j++) {
+ IFeatureReference cref = crefs[j];
+ IFeature cfeature = cref.getFeature(null);
+ features.add(cfeature);
+ }
+ }
+
+ return features;
+ }
+
+ /*
+ * Compute the nested feature subtree starting at the specified base
+ * feature
+ */
+ public static ArrayList computeFeatureSubtree(
+ IFeature top,
+ IFeature feature,
+ ArrayList features,
+ boolean tolerateMissingChildren,
+ ArrayList configuredFeatures,
+ ArrayList visitedFeatures)
+ throws CoreException {
+
+ // check arguments
+ if (top == null)
+ return features;
+ if (feature == null)
+ feature = top;
+ if (features == null)
+ features = new ArrayList();
+ if (visitedFeatures == null)
+ visitedFeatures = new ArrayList();
+
+ // check for <includes> cycle
+ if (visitedFeatures.contains(feature)) {
+ IStatus status =
+ createStatus(top, FeatureStatus.CODE_CYCLE, Messages.ActivityConstraints_cycle);
+ throw new CoreException(status);
+ } else {
+ // keep track of visited features so we can detect cycles
+ visitedFeatures.add(feature);
+ }
+
+ // return specified base feature and all its children
+ if (!features.contains(feature))
+ features.add(feature);
+ IIncludedFeatureReference[] children =
+ feature.getIncludedFeatureReferences();
+ for (int i = 0; i < children.length; i++) {
+ try {
+ IFeature child = UpdateUtils.getIncludedFeature(feature, children[i]);
+ features =
+ computeFeatureSubtree(
+ top,
+ child,
+ features,
+ tolerateMissingChildren,
+ null,
+ visitedFeatures);
+ } catch (CoreException e) {
+ if (!children[i].isOptional() && !tolerateMissingChildren)
+ throw e;
+ }
+ }
+ // no cycles for this feature during DFS
+ visitedFeatures.remove(feature);
+ return features;
+ }
+
+ private static void checkLicense(IFeature feature, ArrayList status) {
+ IURLEntry licenseEntry = feature.getLicense();
+ if (licenseEntry != null) {
+ String license = licenseEntry.getAnnotation();
+ if (license != null && license.trim().length() > 0)
+ return;
+ }
+ status.add(
+ createStatus(feature, FeatureStatus.CODE_OTHER, Messages.ActivityConstraints_noLicense));
+ }
+
+ /*
+ * Compute a list of features that will be configured after the operation
+ */
+ private static ArrayList computeFeaturesAfterOperation(
+ ArrayList features,
+ IFeature add,
+ IFeature remove)
+ throws CoreException {
+
+ ArrayList addTree = computeFeatureSubtree(add, null, null, false,
+ /* do not tolerate missing children */
+ features, null);
+ ArrayList removeTree =
+ computeFeatureSubtree(
+ remove,
+ null,
+ null,
+ true /* tolerate missing children */,
+ null,
+ null
+ );
+ if (remove != null) {
+ // Patches to features are removed together with
+ // those features. Include them in the list.
+ contributePatchesFor(removeTree, features, removeTree);
+ }
+
+ if (remove != null)
+ features.removeAll(removeTree);
+
+ if (add != null)
+ features.addAll(addTree);
+
+ return features;
+ }
+
+ private static void contributePatchesFor(
+ ArrayList removeTree,
+ ArrayList features,
+ ArrayList result)
+ throws CoreException {
+
+ for (int i = 0; i < removeTree.size(); i++) {
+ IFeature feature = (IFeature) removeTree.get(i);
+ contributePatchesFor(feature, features, result);
+ }
+ }
+
+ private static void contributePatchesFor(
+ IFeature feature,
+ ArrayList features,
+ ArrayList result)
+ throws CoreException {
+ for (int i = 0; i < features.size(); i++) {
+ IFeature candidate = (IFeature) features.get(i);
+ if (UpdateUtils.isPatch(feature, candidate)) {
+ ArrayList removeTree =
+ computeFeatureSubtree(candidate, null, null, true,null,null);
+ result.addAll(removeTree);
+ }
+ }
+ }
+
+ /*
+ * Compute a list of features that will be configured after performing the
+ * revert
+ */
+ private static ArrayList computeFeaturesAfterRevert(IInstallConfiguration config)
+ throws CoreException {
+
+ ArrayList list = new ArrayList();
+ IConfiguredSite[] csites = config.getConfiguredSites();
+ for (int i = 0; i < csites.length; i++) {
+ IConfiguredSite csite = csites[i];
+ IFeatureReference[] features = csite.getConfiguredFeatures();
+ for (int j = 0; j < features.length; j++) {
+ list.add(features[j].getFeature(null));
+ }
+ }
+ return list;
+ }
+
+
+
+ /*
+ * Compute a list of plugin entries for the specified features.
+ */
+ private static ArrayList computePluginsForFeatures(ArrayList features)
+ throws CoreException {
+ if (features == null)
+ return new ArrayList();
+
+ HashMap plugins = new HashMap();
+ for (int i = 0; i < features.size(); i++) {
+ IFeature feature = (IFeature) features.get(i);
+ IPluginEntry[] entries = feature.getPluginEntries();
+ for (int j = 0; j < entries.length; j++) {
+ IPluginEntry entry = entries[j];
+ plugins.put(entry.getVersionedIdentifier(), entry);
+ }
+ }
+ ArrayList result = new ArrayList();
+ result.addAll(plugins.values());
+ return result;
+ }
+
+
+ /**
+ * Check for feature cycles:
+ * - visit feature
+ * - if feature is in the cycle candidates list, then cycle found, else add it to candidates list
+ * - DFS children
+ * - when return from DFS remove the feature from the candidates list
+ */
+ private static void checkForCycles(
+ IFeature feature,
+ ArrayList candidates,
+ ArrayList configuredFeatures)
+ throws CoreException {
+
+ // check arguments
+ if (feature == null)
+ return;
+ if (configuredFeatures == null)
+ configuredFeatures = new ArrayList();
+ if (candidates == null)
+ candidates = new ArrayList();
+
+ // check for <includes> cycle
+ if (candidates.contains(feature)) {
+ String msg = NLS.bind(Messages.ActivityConstraints_cycle, (new String[] {feature.getLabel(),
+ feature.getVersionedIdentifier().toString()}));
+ IStatus status = createStatus(feature, FeatureStatus.CODE_CYCLE, msg);
+ throw new CoreException(status);
+ }
+
+ // potential candidate
+ candidates.add(feature);
+
+ // recursively, check cycles with children
+ IIncludedFeatureReference[] children =
+ feature.getIncludedFeatureReferences();
+ for (int i = 0; i < children.length; i++) {
+ try {
+ IFeature child = UpdateUtils.getIncludedFeature(feature, children[i]);
+ checkForCycles(child, candidates, configuredFeatures);
+ } catch (CoreException e) {
+ if (!children[i].isOptional())
+ throw e;
+ }
+ }
+ // no longer a candidate, because no cycles with children
+ candidates.remove(feature);
+ }
+
+ /*
+ * validate constraints
+ */
+ private static Set checkConstraints(ArrayList features, ArrayList status)
+ throws CoreException {
+ if (features == null)
+ return Collections.EMPTY_SET;
+
+ ArrayList plugins = computePluginsForFeatures(features);
+
+ checkEnvironment(features, status);
+ checkPlatformFeature(features, plugins, status);
+ checkPrimaryFeature(features, plugins, status);
+ return checkPrereqs(features, plugins, status);
+ }
+
+ /*
+ * Verify all features are either portable, or match the current
+ * environment
+ */
+ private static void checkEnvironment(
+ ArrayList features,
+ ArrayList status) {
+
+ String os = Platform.getOS();
+ String ws = Platform.getWS();
+ String arch = Platform.getOSArch();
+
+ for (int i = 0; i < features.size(); i++) {
+ IFeature feature = (IFeature) features.get(i);
+ ArrayList fos = createList(feature.getOS());
+ ArrayList fws = createList(feature.getWS());
+ ArrayList farch = createList(feature.getOSArch());
+
+ if (fos.size() > 0) {
+ if (!fos.contains(os)) {
+ IStatus s =
+ createStatus(feature, FeatureStatus.CODE_ENVIRONMENT, Messages.ActivityConstraints_os);
+ if (!status.contains(s))
+ status.add(s);
+ continue;
+ }
+ }
+
+ if (fws.size() > 0) {
+ if (!fws.contains(ws)) {
+ IStatus s =
+ createStatus(feature, FeatureStatus.CODE_ENVIRONMENT, Messages.ActivityConstraints_ws);
+ if (!status.contains(s))
+ status.add(s);
+ continue;
+ }
+ }
+
+ if (farch.size() > 0) {
+ if (!farch.contains(arch)) {
+ IStatus s =
+ createStatus(feature, FeatureStatus.CODE_ENVIRONMENT, Messages.ActivityConstraints_arch);
+ if (!status.contains(s))
+ status.add(s);
+ continue;
+ }
+ }
+ }
+ }
+
+ /*
+ * Verify we end up with a version of platform configured
+ */
+ private static void checkPlatformFeature(
+ ArrayList features,
+ ArrayList plugins,
+ ArrayList status) {
+
+ // find the plugin that defines the product
+ IProduct product = Platform.getProduct();
+ if (product == null)
+ return; // normally this shouldn't happen
+ Bundle primaryBundle = product.getDefiningBundle();
+ // check if that plugin is among the resulting plugins
+ boolean found = false;
+ for (int j = 0; j < plugins.size(); j++) {
+ IPluginEntry plugin = (IPluginEntry) plugins.get(j);
+ if (primaryBundle.getSymbolicName().equals(plugin.getVersionedIdentifier().getIdentifier())) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ IStatus s =
+ createStatus(null, FeatureStatus.CODE_OTHER, Messages.ActivityConstraints_platform);
+ if (!status.contains(s))
+ status.add(s);
+ }
+ }
+
+ /*
+ * Verify we end up with a version of primary feature configured
+ */
+ private static void checkPrimaryFeature(
+ ArrayList features,
+ ArrayList plugins,
+ ArrayList status) {
+
+ String featureId =
+ ConfiguratorUtils
+ .getCurrentPlatformConfiguration()
+ .getPrimaryFeatureIdentifier();
+
+ if (featureId != null) {
+ // primary feature is defined
+ for (int i = 0; i < features.size(); i++) {
+ IFeature feature = (IFeature) features.get(i);
+ if (featureId
+ .equals(feature.getVersionedIdentifier().getIdentifier()))
+ return;
+ }
+
+ IStatus s = createStatus(null, FeatureStatus.CODE_OTHER, Messages.ActivityConstraints_primary);
+ if (!status.contains(s))
+ status.add(s);
+ } else {
+ // check if the product still ends up contributed
+ // find the plugin that defines the product
+ IProduct product = Platform.getProduct();
+ if (product == null)
+ return; // normally this shouldn't happen
+ Bundle primaryBundle = product.getDefiningBundle();
+ // check if that plugin is among the resulting plugins
+
+ for (int j = 0; j < plugins.size(); j++) {
+ IPluginEntry plugin = (IPluginEntry) plugins.get(j);
+ if (primaryBundle.getSymbolicName().equals(plugin.getVersionedIdentifier().getIdentifier())) {
+ return; // product found
+ }
+ }
+ IStatus s =
+ createStatus(null, FeatureStatus.CODE_OTHER, Messages.ActivityConstraints_primary);
+ if (!status.contains(s))
+ status.add(s);
+ }
+ }
+
+ /*
+ * Verify we do not break prereqs
+ */
+ private static Set checkPrereqs(
+ ArrayList features,
+ ArrayList plugins,
+ ArrayList status) {
+
+ HashSet result = new HashSet();
+
+ for (int i = 0; i < features.size(); i++) {
+ IFeature feature = (IFeature) features.get(i);
+ IImport[] imports = feature.getImports();
+
+ for (int j = 0; j < imports.length; j++) {
+ IImport iimport = imports[j];
+ // for each import determine plugin or feature, version, match
+ // we need
+ VersionedIdentifier iid = iimport.getVersionedIdentifier();
+ String id = iid.getIdentifier();
+ PluginVersionIdentifier version = iid.getVersion();
+ boolean featurePrereq =
+ iimport.getKind() == IImport.KIND_FEATURE;
+ boolean ignoreVersion =
+ version.getMajorComponent() == 0
+ && version.getMinorComponent() == 0
+ && version.getServiceComponent() == 0;
+ int rule = iimport.getRule();
+ if (rule == IUpdateConstants.RULE_NONE)
+ rule = IUpdateConstants.RULE_COMPATIBLE;
+
+ boolean found = false;
+
+ ArrayList candidates;
+
+ if (featurePrereq)
+ candidates = features;
+ else
+ candidates = plugins;
+ for (int k = 0; k < candidates.size(); k++) {
+ VersionedIdentifier cid;
+ if (featurePrereq) {
+ // the candidate is a feature
+ IFeature candidate = (IFeature) candidates.get(k);
+ // skip self
+ if (feature.equals(candidate))
+ continue;
+ cid = candidate.getVersionedIdentifier();
+ } else {
+ // the candidate is a plug-in
+ IPluginEntry plugin = (IPluginEntry) candidates.get(k);
+ cid = plugin.getVersionedIdentifier();
+ }
+ PluginVersionIdentifier cversion = cid.getVersion();
+ if (id.equals(cid.getIdentifier())) {
+ // have a candidate
+ if (ignoreVersion)
+ found = true;
+ else if (
+ rule == IUpdateConstants.RULE_PERFECT
+ && cversion.isPerfect(version))
+ found = true;
+ else if (
+ rule == IUpdateConstants.RULE_EQUIVALENT
+ && cversion.isEquivalentTo(version))
+ found = true;
+ else if (
+ rule == IUpdateConstants.RULE_COMPATIBLE
+ && cversion.isCompatibleWith(version))
+ found = true;
+ else if (
+ rule == IUpdateConstants.RULE_GREATER_OR_EQUAL
+ && cversion.isGreaterOrEqualTo(version))
+ found = true;
+ }
+ if (found)
+ break;
+ }
+
+ // perhaps the bundle that we are looking for was installed
+ // but isn't a part of a feature
+ if (!found && !featurePrereq)
+ found = isInstalled(iid, rule, ignoreVersion);
+
+ if (!found) {
+ // report status
+ String target =
+ featurePrereq
+ ? Messages.ActivityConstaints_prereq_feature
+ : Messages.ActivityConstaints_prereq_plugin;
+ int errorCode = featurePrereq
+ ? FeatureStatus.CODE_PREREQ_FEATURE
+ : FeatureStatus.CODE_PREREQ_PLUGIN;
+ String msg =
+ NLS.bind(Messages.ActivityConstraints_prereq, (new String[] { target, id }));
+
+ if (!ignoreVersion) {
+ if (rule == IUpdateConstants.RULE_PERFECT)
+ msg =
+ NLS.bind(Messages.ActivityConstraints_prereqPerfect, (new String[] {
+ target,
+ id,
+ version.toString()}));
+ else if (rule == IUpdateConstants.RULE_EQUIVALENT)
+ msg =
+ NLS.bind(Messages.ActivityConstraints_prereqEquivalent, (new String[] {
+ target,
+ id,
+ version.toString()}));
+ else if (rule == IUpdateConstants.RULE_COMPATIBLE)
+ msg =
+ NLS.bind(Messages.ActivityConstraints_prereqCompatible, (new String[] {
+ target,
+ id,
+ version.toString()}));
+ else if (rule == IUpdateConstants.RULE_GREATER_OR_EQUAL)
+ msg =
+ NLS.bind(Messages.ActivityConstraints_prereqGreaterOrEqual, (new String[] {
+ target,
+ id,
+ version.toString()}));
+ }
+ IStatus s = createStatus(feature, errorCode, msg);
+ result.add(new InternalImport(iimport));
+ if (!status.contains(s))
+ status.add(s);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /*
+ * Return a boolean value indicating whether or not the bundle with the given id and version
+ * is installed in the system.
+ */
+ private static boolean isInstalled(VersionedIdentifier vid, int rule, boolean ignoreVersion) {
+ BundleContext context = UpdateCore.getPlugin().getBundleContext();
+ if (context == null)
+ return false;
+ ServiceReference reference = context.getServiceReference(PlatformAdmin.class.getName());
+ if (reference == null)
+ return false;
+ PlatformAdmin admin = (PlatformAdmin) context.getService(reference);
+ try {
+ State state = admin.getState(false);
+ String id = vid.getIdentifier();
+ PluginVersionIdentifier version = vid.getVersion();
+ BundleDescription[] bundles = state.getBundles(id);
+ if (bundles == null || bundles.length == 0)
+ return false;
+ for (int i=0; i<bundles.length; i++) {
+ BundleDescription bundle = bundles[i];
+ PluginVersionIdentifier cversion = new PluginVersionIdentifier(bundle.getVersion().toString());
+ // have a candidate
+ if (ignoreVersion)
+ return true;
+ if (rule == IUpdateConstants.RULE_PERFECT && cversion.isPerfect(version))
+ return true;
+ else if (rule == IUpdateConstants.RULE_EQUIVALENT && cversion.isEquivalentTo(version))
+ return true;
+ else if (rule == IUpdateConstants.RULE_COMPATIBLE && cversion.isCompatibleWith(version))
+ return true;
+ else if (rule == IUpdateConstants.RULE_GREATER_OR_EQUAL && cversion.isGreaterOrEqualTo(version))
+ return true;
+ }
+ return false;
+ } finally {
+ context.ungetService(reference);
+ }
+ }
+
+ /*
+ * Verify we end up with valid nested features after revert
+ */
+ private static void checkRevertConstraints(
+ ArrayList features,
+ ArrayList status) {
+
+ for (int i = 0; i < features.size(); i++) {
+ IFeature feature = (IFeature) features.get(i);
+ try {
+ computeFeatureSubtree(
+ feature,
+ null,
+ null,
+ false /* do not tolerate missing children */,
+ null,
+ null
+ );
+ } catch (CoreException e) {
+ status.add(e.getStatus());
+ }
+ }
+ }
+
+ /*
+ * Verify that a parent of an optional child is configured before we allow
+ * the child to be configured as well
+ */
+
+ private static void checkOptionalChildConfiguring(
+ IFeature feature,
+ ArrayList status)
+ throws CoreException {
+ ILocalSite localSite = SiteManager.getLocalSite();
+ IInstallConfiguration config = localSite.getCurrentConfiguration();
+ IConfiguredSite[] csites = config.getConfiguredSites();
+
+ boolean included = false;
+ for (int i = 0; i < csites.length; i++) {
+ IConfiguredSite csite = csites[i];
+ ISiteFeatureReference[] crefs =
+ csite.getSite().getFeatureReferences();
+ for (int j = 0; j < crefs.length; j++) {
+ IFeatureReference cref = crefs[j];
+ IFeature cfeature = null;
+ try {
+ cfeature = cref.getFeature(null);
+ } catch (CoreException e) {
+ //FIXME: cannot ask 'isOptional' here
+ // Ignore missing optional feature.
+ /*
+ * if (cref.isOptional()) continue;
+ */
+ throw e;
+ }
+ if (isParent(cfeature, feature, true)) {
+ // Included in at least one feature as optional
+ included = true;
+ if (csite.isConfigured(cfeature)) {
+ // At least one feature parent
+ // is enabled - it is OK to
+ // configure optional child.
+ return;
+ }
+ }
+ }
+ }
+ if (included) {
+ // feature is included as optional but
+ // no parent is currently configured.
+ String msg = Messages.ActivityConstraints_optionalChild;
+ status.add(createStatus(feature, FeatureStatus.CODE_OPTIONAL_CHILD, msg));
+ } else {
+ //feature is root - can be configured
+ }
+ }
+//
+// /**
+// * Checks if the configuration is locked by other instances
+// *
+// * @param status
+// */
+// private static void checkConfigurationLock(ArrayList status) {
+// IPlatformConfiguration config =
+// BootLoader.getCurrentPlatformConfiguration();
+// URL configURL = config.getConfigurationLocation();
+// if (!"file".equals(configURL.getProtocol())) {
+// status.add(
+// createStatus(
+// null,
+// "Configuration location is not writable:" + configURL));
+// return;
+// }
+// String locationString = configURL.getFile();
+// File configDir = new File(locationString);
+// if (!configDir.isDirectory())
+// configDir = configDir.getParentFile();
+// if (!configDir.exists()) {
+// status.add(
+// createStatus(null, "Configuration location does not exist"));
+// return;
+// }
+// File locksDir = new File(configDir, "locks");
+// // check all the possible lock files
+// File[] lockFiles = locksDir.listFiles();
+// File configLock = BootLoader.getCurrentPlatformConfiguration().getLockFile();
+// for (int i = 0; i < lockFiles.length; i++) {
+// if (lockFiles[i].equals(configLock))
+// continue;
+// try {
+// RandomAccessFile raf = new RandomAccessFile(lockFiles[i], "rw");
+// FileChannel channel = raf.getChannel();
+// System.out.println(channel.isOpen());
+// FileLock lock = channel.tryLock();
+// if (lock == null){
+// // there is another eclipse instance running
+// raf.close();
+// status.add(
+// createStatus(
+// null,
+// "Another instance is running, please close it before performing any configuration operations"));
+// return;
+// }
+//
+// } catch (Exception e) {
+// status.add(createStatus(null, "Failed to create lock:"+lockFiles[i]));
+// return;
+// }
+// }
+// }
+
+ private static boolean isParent(
+ IFeature candidate,
+ IFeature feature,
+ boolean optionalOnly)
+ throws CoreException {
+ IIncludedFeatureReference[] refs =
+ candidate.getIncludedFeatureReferences();
+ for (int i = 0; i < refs.length; i++) {
+ IIncludedFeatureReference child = refs[i];
+ VersionedIdentifier fvid = feature.getVersionedIdentifier();
+ VersionedIdentifier cvid = child.getVersionedIdentifier();
+
+ if (fvid.getIdentifier().equals(cvid.getIdentifier()) == false)
+ continue;
+ // same ID
+ PluginVersionIdentifier fversion = fvid.getVersion();
+ PluginVersionIdentifier cversion = cvid.getVersion();
+
+ if (fversion.equals(cversion)) {
+ // included and matched; return true if optionality is not
+ // important or it is and the inclusion is optional
+ return optionalOnly == false || child.isOptional();
+ }
+ }
+ return false;
+ }
+
+// private static boolean checkTimeline(
+// IInstallConfiguration config,
+// ArrayList status) {
+// try {
+// ILocalSite lsite = SiteManager.getLocalSite();
+// IInstallConfiguration cconfig = lsite.getCurrentConfiguration();
+// if (cconfig.getTimeline() != config.getTimeline()) {
+// // Not the same timeline - cannot revert
+// String msg =
+// UpdateUtils.getFormattedMessage(
+// KEY_WRONG_TIMELINE,
+// config.getLabel());
+// status.add(createStatus(null, FeatureStatus.CODE_OTHER, msg));
+// return false;
+// }
+// } catch (CoreException e) {
+// status.add(e.getStatus());
+// }
+// return true;
+// }
+
+ private static IStatus createMultiStatus(
+ String message,
+ ArrayList children,
+ int code) {
+ IStatus[] carray =
+ (IStatus[]) children.toArray(new IStatus[children.size()]);
+ return new MultiStatus(
+ UpdateCore.getPlugin().getBundle().getSymbolicName(),
+ code,
+ carray,
+ message,
+ null);
+ }
+
+ private static IStatus createStatus(IFeature feature, int errorCode, String message) {
+
+ String fullMessage;
+ if (feature == null)
+ fullMessage = message;
+ else {
+ PluginVersionIdentifier version =
+ feature.getVersionedIdentifier().getVersion();
+ fullMessage =
+ NLS.bind(Messages.ActivityConstraints_childMessage, (new String[] {
+ feature.getLabel(),
+ version.toString(),
+ message }));
+ }
+
+ return new FeatureStatus(
+ feature,
+ IStatus.ERROR,
+ UpdateCore.getPlugin().getBundle().getSymbolicName(),
+ errorCode,
+ fullMessage,
+ null);
+ }
+
+ // private static IStatus createReportStatus(ArrayList beforeStatus,
+ // ArrayList status) {
+ // // report status
+ // if (status.size() > 0) {
+ // if (beforeStatus.size() > 0)
+ // return createMultiStatus(KEY_ROOT_MESSAGE_INIT,
+ // beforeStatus,IStatus.ERROR);
+ // else
+ // return createMultiStatus(KEY_ROOT_MESSAGE, status,IStatus.ERROR);
+ // }
+ // return null;
+ // }
+
+ private static IStatus createCombinedReportStatus(
+ ArrayList beforeStatus,
+ ArrayList status) {
+ if (beforeStatus.size() == 0) { // good initial config
+ if (status.size() == 0) {
+ return null; // all fine
+ } else {
+ return createMultiStatus(Messages.ActivityConstraints_rootMessage,
+ status,
+ IStatus.ERROR);
+ // error after operation
+ }
+ } else { // beforeStatus.size() > 0 : initial config errors
+ if (status.size() == 0) {
+ return null; // errors will be fixed
+ } else {
+ if (isBetterStatus(beforeStatus, status)) {
+ return createMultiStatus(
+ Messages.ActivityConstraints_warning,
+ beforeStatus,
+ IStatus.WARNING);
+ // errors may be fixed
+ } else {
+ ArrayList combined = new ArrayList();
+ combined.add(
+ createMultiStatus(
+ Messages.ActivityConstraints_beforeMessage,
+ beforeStatus,
+ IStatus.ERROR));
+ combined.add(
+ createMultiStatus(
+ Messages.ActivityConstraints_afterMessage,
+ status,
+ IStatus.ERROR));
+ return createMultiStatus(
+ Messages.ActivityConstraints_rootMessageInitial,
+ combined,
+ IStatus.ERROR);
+ }
+ }
+ }
+ }
+
+ private static ArrayList createList(String commaSeparatedList) {
+ ArrayList list = new ArrayList();
+ if (commaSeparatedList != null) {
+ StringTokenizer t =
+ new StringTokenizer(commaSeparatedList.trim(), ","); //$NON-NLS-1$
+ while (t.hasMoreTokens()) {
+ String token = t.nextToken().trim();
+ if (!token.equals("")) //$NON-NLS-1$
+ list.add(token);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Returns true if status is a subset of beforeStatus
+ *
+ * @param beforeStatus
+ * @param status
+ * @return
+ */
+ private static boolean isBetterStatus(
+ ArrayList beforeStatus,
+ ArrayList status) {
+ // if no status at all, then it's a subset
+ if (status == null || status.size() == 0)
+ return true;
+ // there is some status, so if there is no initial status, then it's
+ // not a subset
+ if (beforeStatus == null || beforeStatus.size() == 0)
+ return false;
+ // quick check
+ if (beforeStatus.size() < status.size())
+ return false;
+
+ // check if all the status elements appear in the original status
+ for (int i = 0; i < status.size(); i++) {
+ IStatus s = (IStatus) status.get(i);
+ // if this is not a feature status, something is wrong, so return
+ // false
+ if (!(s instanceof FeatureStatus))
+ return false;
+ FeatureStatus fs = (FeatureStatus) s;
+ // check against all status elements
+ boolean found = false;
+ for (int j = 0; !found && j < beforeStatus.size(); j++) {
+ if (fs.equals(beforeStatus.get(j)))
+ found = true;
+ }
+ if (!found)
+ return false;
+ }
+ return true;
+ }
+
+ public class RequiredFeaturesResult {
+
+ private IStatus status;
+ private Set requiredFeatures;
+
+ public Set getRequiredFeatures() {
+ return requiredFeatures;
+ }
+ public void setRequiredFeatures(Set requiredFeatures) {
+ this.requiredFeatures = requiredFeatures;
+ }
+ public void addRequiredFeatures(Set requiredFeatures) {
+ if (requiredFeatures == null) {
+ requiredFeatures = new HashSet();
+ }
+ this.requiredFeatures.addAll(requiredFeatures);
+ }
+ public IStatus getStatus() {
+ return status;
+ }
+ public void setStatus(IStatus status) {
+ this.status = status;
+ }
+
+
+ }
+
+ public static class InternalImport {
+
+ private IImport iimport;
+
+ public InternalImport(IImport iimport) {
+ this.iimport = iimport;
+ }
+
+ public IImport getImport() {
+ return iimport;
+ }
+
+ public void setImport(IImport iimport) {
+ this.iimport = iimport;
+ }
+
+ public boolean equals(Object object) {
+
+ if ( ( object == null) || !(object instanceof InternalImport))
+ return false;
+
+ if ( object == this)
+ return true;
+
+ return iimport.getVersionedIdentifier().equals( ((InternalImport)object).getImport().getVersionedIdentifier()) && (getImport().getRule() == ((InternalImport)object).getImport().getRule());
+
+ }
+
+ public int hashCode() {
+ return iimport.getVersionedIdentifier().hashCode() * iimport.getRule();
+ }
+
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/PatchCleaner.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/PatchCleaner.java
new file mode 100644
index 0000000..91f419c
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/PatchCleaner.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.operations;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+
+/**
+ * This utility class attaches as a listened to the provided
+ * configured site, and for every unconfigured feature
+ * it tests if it is a patch and cleans up its backup configuration.
+ */
+
+public class PatchCleaner {
+ private IConfiguredSite csite;
+ private SiteListener listener;
+ class SiteListener implements IConfiguredSiteChangedListener {
+ public void featureInstalled(IFeature feature) {
+ }
+ public void featureRemoved(IFeature feature) {
+ cleanSavedConfigs(feature);
+ }
+ public void featureConfigured(IFeature feature) {
+ }
+ public void featureUnconfigured(IFeature feature) {
+ cleanSavedConfigs(feature);
+ }
+ }
+ public PatchCleaner(IConfiguredSite csite, IFeature root) {
+ this.csite = csite;
+ listener = new SiteListener();
+ csite.addConfiguredSiteChangedListener(listener);
+ }
+
+ public void dispose() {
+ csite.removeConfiguredSiteChangedListener(listener);
+ }
+ private void cleanSavedConfigs(IFeature feature) {
+ if (feature.isPatch()) {
+ IInstallConfiguration backupConfig = UpdateUtils.getBackupConfigurationFor(feature);
+ if (backupConfig!=null) {
+ // clean it
+ remove(backupConfig);
+ }
+ }
+ }
+ private void remove(IInstallConfiguration config) {
+ try {
+ ILocalSite localSite = SiteManager.getLocalSite();
+ localSite.removeFromPreservedConfigurations(config);
+ }
+ catch (CoreException e) {
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/ReplaceFeatureVersionOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/ReplaceFeatureVersionOperation.java
new file mode 100644
index 0000000..6d5858b
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/ReplaceFeatureVersionOperation.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.operations;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.operations.*;
+
+/**
+ * Swaps a feature.
+ * ReplaceFeatureVersionOperation
+ */
+public class ReplaceFeatureVersionOperation
+ extends FeatureOperation
+ implements IConfigFeatureOperation {
+
+ private IFeature anotherFeature;
+
+ public ReplaceFeatureVersionOperation(
+ IFeature feature,
+ IFeature anotherFeature) {
+ super(feature.getSite().getCurrentConfiguredSite(), feature);
+ this.anotherFeature = anotherFeature;
+ }
+
+ public boolean execute(IProgressMonitor pm, IOperationListener listener)
+ throws CoreException {
+
+ IStatus status =
+ OperationsManager.getValidator().validatePendingReplaceVersion(feature, anotherFeature);
+ if (status != null) {
+ throw new CoreException(status);
+ }
+
+ // unconfigure current feature first, then configure the other one
+
+ PatchCleaner cleaner = new PatchCleaner(targetSite, feature);
+ targetSite.unconfigure(feature);
+ cleaner.dispose();
+
+ targetSite.configure(anotherFeature);
+// ensureUnique();
+
+ try {
+ // Restart not needed
+ boolean restartNeeded = false;
+
+ // Check if this operation is cancelling one that's already pending
+ IOperation pendingOperation =
+ OperationsManager.findPendingOperation(feature);
+
+ if (pendingOperation instanceof IConfigFeatureOperation) {
+ // no need to do either pending change
+ OperationsManager.removePendingOperation(pendingOperation);
+ } else {
+ OperationsManager.addPendingOperation(this);
+ restartNeeded = true;
+ }
+
+ pendingOperation =
+ OperationsManager.findPendingOperation(anotherFeature);
+
+ if (pendingOperation instanceof IUnconfigFeatureOperation) {
+ // no need to do either pending change
+ OperationsManager.removePendingOperation(pendingOperation);
+ } else {
+ OperationsManager.addPendingOperation(this);
+ restartNeeded = true;
+ }
+
+ markProcessed();
+ if (listener != null)
+ listener.afterExecute(this, null);
+
+ restartNeeded = SiteManager.getLocalSite().save() && restartNeeded;
+
+ // notify the model
+ OperationsManager.fireObjectChanged(feature, null);
+
+ return restartNeeded;
+ } catch (CoreException e) {
+ undo();
+ UpdateUtils.logException(e);
+ throw e;
+ }
+ }
+
+ public void undo() throws CoreException {
+ targetSite.unconfigure(anotherFeature);
+ targetSite.configure(feature);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/RevertConfigurationOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/RevertConfigurationOperation.java
new file mode 100644
index 0000000..83e9702
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/RevertConfigurationOperation.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.operations;
+
+import java.lang.reflect.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.operations.*;
+
+public class RevertConfigurationOperation extends Operation implements IRevertConfigurationOperation {
+
+ private IInstallConfiguration config;
+ private IProblemHandler problemHandler;
+
+ public RevertConfigurationOperation(
+ IInstallConfiguration config,
+ IProblemHandler problemHandler) {
+ super();
+ this.config = config;
+ this.problemHandler = problemHandler;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.operations.IOperation#execute(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public boolean execute(IProgressMonitor monitor, IOperationListener listener)
+ throws CoreException, InvocationTargetException {
+ IStatus status =
+ OperationsManager.getValidator().validatePendingRevert(config);
+ if (status != null && status.getCode() == IStatus.ERROR) {
+ throw new CoreException(status);
+ }
+
+ try {
+ ILocalSite localSite = SiteManager.getLocalSite();
+ localSite.revertTo(config, monitor, problemHandler);
+ localSite.save();
+ return true;
+ } catch (CoreException e) {
+ UpdateUtils.logException(e);
+ throw e;
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/ToggleSiteOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/ToggleSiteOperation.java
new file mode 100644
index 0000000..d9fcd21
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/ToggleSiteOperation.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.operations;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.operations.*;
+
+public class ToggleSiteOperation
+ extends Operation
+ implements IToggleSiteOperation {
+
+ private IConfiguredSite site;
+
+ public ToggleSiteOperation(IConfiguredSite site) {
+ super();
+ this.site = site;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.operations.IOperation#execute(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public boolean execute(
+ IProgressMonitor monitor,
+ IOperationListener listener)
+ throws CoreException {
+ if (site == null)
+ return false;
+ boolean oldValue = site.isEnabled();
+ site.setEnabled(!oldValue);
+ IStatus status = OperationsManager.getValidator().validateCurrentState();
+ if (status != null) {
+ // revert
+ site.setEnabled(oldValue);
+ throw new CoreException(status);
+ } else {
+ try {
+ boolean restartNeeded = SiteManager.getLocalSite().save();
+ OperationsManager.fireObjectChanged(site, ""); //$NON-NLS-1$
+ return restartNeeded; // will restart only if changes could not be applied to current config
+ } catch (CoreException e) {
+ //revert
+ site.setEnabled(oldValue);
+ UpdateUtils.logException(e);
+ throw e;
+ }
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UnconfigOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UnconfigOperation.java
new file mode 100644
index 0000000..f0c8808
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UnconfigOperation.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.operations;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.operations.*;
+
+/**
+ * Unconfigure a feature.
+ * UnconfigOperation
+ */
+public class UnconfigOperation
+ extends FeatureOperation
+ implements IUnconfigFeatureOperation {
+
+ public UnconfigOperation(
+ IConfiguredSite site,
+ IFeature feature) {
+ super(site, feature);
+ }
+
+ public boolean execute(IProgressMonitor pm, IOperationListener listener)
+ throws CoreException {
+
+ IStatus status =
+ OperationsManager.getValidator().validatePendingUnconfig(feature);
+ if (status != null && status.getCode() == IStatus.ERROR) {
+ throw new CoreException(status);
+ }
+
+ PatchCleaner cleaner = new PatchCleaner(targetSite, feature);
+ targetSite.unconfigure(feature);
+ cleaner.dispose();
+
+ try {
+ // Restart not needed
+ boolean restartNeeded = false;
+
+ // Check if this operation is cancelling one that's already pending
+ IOperation pendingOperation =
+ OperationsManager.findPendingOperation(feature);
+
+ if (pendingOperation instanceof IConfigFeatureOperation) {
+ // no need to do either pending change
+ OperationsManager.removePendingOperation(pendingOperation);
+ } else {
+ OperationsManager.addPendingOperation(this);
+ restartNeeded = true;
+ }
+
+ markProcessed();
+ if (listener != null)
+ listener.afterExecute(this, null);
+
+ restartNeeded = SiteManager.getLocalSite().save() && restartNeeded;
+
+ // notify the model
+ OperationsManager.fireObjectChanged(feature, null);
+
+ return restartNeeded;
+ } catch (CoreException e) {
+ undo();
+ UpdateUtils.logException(e);
+ throw e;
+ }
+ }
+
+ public void undo() throws CoreException {
+ targetSite.configure(feature);
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UnconfigureAndUninstallFeatureOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UnconfigureAndUninstallFeatureOperation.java
new file mode 100644
index 0000000..ed22c60
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UnconfigureAndUninstallFeatureOperation.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.update.internal.operations;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.util.Properties;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.configurator.ConfiguratorUtils;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.operations.IOperationListener;
+import org.eclipse.update.operations.IUnconfigFeatureOperation;
+import org.eclipse.update.operations.OperationsManager;
+
+public class UnconfigureAndUninstallFeatureOperation extends FeatureOperation
+ implements IUnconfigureAndUninstallFeatureOperation {
+
+ public UnconfigureAndUninstallFeatureOperation(IConfiguredSite targetSite, IFeature feature) {
+ super(targetSite, feature);
+ }
+
+ public boolean execute(IProgressMonitor pm, IOperationListener listener)
+ throws CoreException, InvocationTargetException {
+
+ IUnconfigFeatureOperation unconfigOperation = OperationsManager.getOperationFactory().createUnconfigOperation(targetSite, feature);
+
+ /*boolean isRestartNeeded = */unconfigOperation.execute(pm, listener);
+
+
+ URL platformXML = ConfiguratorUtils.getCurrentPlatformConfiguration().getConfigurationLocation();
+
+ File f = new File(platformXML.getFile());
+
+ f = new File(f.getParentFile(), "toBeUninstalled"); //$NON-NLS-1$
+ try {
+ if (!f.exists()) {
+ f.createNewFile();
+ }
+ FileInputStream fis = new FileInputStream(f);
+ Properties toBeUninstalled = new Properties();
+ toBeUninstalled.load(fis);
+ toBeUninstalled.put(new Integer(toBeUninstalled.size()+1).toString(), targetSite.getSite().getURL() + ";" + feature.getVersionedIdentifier().toString()); //$NON-NLS-1$
+ fis.close();
+ FileOutputStream fos = new FileOutputStream(f);
+ toBeUninstalled.store(fos, "to be uninstalled on start-up"); //$NON-NLS-1$
+ fos.close();
+
+ } catch (IOException ioe) {
+
+ }
+
+
+ return true;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UnconfigureAndUninstallFeaturesOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UnconfigureAndUninstallFeaturesOperation.java
new file mode 100644
index 0000000..a96108f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UnconfigureAndUninstallFeaturesOperation.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.update.internal.operations;
+
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.operations.IOperation;
+import org.eclipse.update.operations.OperationsManager;
+
+public class UnconfigureAndUninstallFeaturesOperation extends
+ BatchFeatureOperation implements
+ IUnconfigureAndUninstallFeaturesOperation {
+
+ public UnconfigureAndUninstallFeaturesOperation(IConfiguredSite[] targetSites,
+ IFeature[] features) {
+ super(targetSites, features);
+ }
+
+ protected IOperation createOperation(IConfiguredSite targetSite, IFeature feature) {
+ return ((OperationFactory)OperationsManager.getOperationFactory()).createUnconfigureAndUninstallFeatureOperation(targetSite, feature);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UnconfigureFeaturesOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UnconfigureFeaturesOperation.java
new file mode 100644
index 0000000..184c8b8
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UnconfigureFeaturesOperation.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.update.internal.operations;
+
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.operations.IOperation;
+import org.eclipse.update.operations.OperationsManager;
+
+public class UnconfigureFeaturesOperation
+ extends BatchFeatureOperation implements IUnconfigureFeaturesOperation {
+
+ public UnconfigureFeaturesOperation(IConfiguredSite[] targetSites, IFeature[] features) {
+ super(targetSites, features);
+ }
+
+ protected IOperation createOperation(IConfiguredSite targetSite, IFeature feature) {
+ return OperationsManager.getOperationFactory().createUnconfigOperation(targetSite, feature);
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UninstallFeaturesOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UninstallFeaturesOperation.java
new file mode 100644
index 0000000..c6879de
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UninstallFeaturesOperation.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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.update.internal.operations;
+
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.operations.IOperation;
+import org.eclipse.update.operations.OperationsManager;
+
+public class UninstallFeaturesOperation extends BatchFeatureOperation implements
+ IUninstallFeaturesOperation {
+
+ public UninstallFeaturesOperation(IConfiguredSite[] targetSites, IFeature[] features) {
+ super(targetSites, features);
+ }
+
+
+ protected IOperation createOperation(IConfiguredSite targetSite, IFeature feature) {
+ return OperationsManager.getOperationFactory().createUninstallOperation(targetSite, feature);
+ }
+
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UninstallOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UninstallOperation.java
new file mode 100644
index 0000000..136b7a4
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UninstallOperation.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.operations;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.operations.*;
+
+/**
+ * Configure a feature.
+ * ConfigOperation
+ */
+public class UninstallOperation extends FeatureOperation implements IUninstallFeatureOperation{
+
+ public UninstallOperation(IConfiguredSite site, IFeature feature) {
+ super(site, feature);
+ }
+
+ public void setTargetSite(IConfiguredSite targetSite) {
+ this.targetSite = targetSite;
+ }
+
+ public boolean execute(IProgressMonitor pm, IOperationListener listener) throws CoreException {
+
+ if (targetSite == null)
+ targetSite = UpdateUtils.getConfigSite(feature, SiteManager.getLocalSite().getCurrentConfiguration());
+
+ // Restart not needed
+ boolean restartNeeded = false;
+
+ if (targetSite != null) {
+ // if needed, unconfigure the feature first
+ if (targetSite.isConfigured(feature)) {
+ IStatus status = OperationsManager.getValidator().validatePendingUnconfig(feature);
+ if (status != null && status.getCode() == IStatus.ERROR)
+ throw new CoreException(status);
+ if (unconfigure(feature, targetSite))
+ restartNeeded = true;
+ else
+ throw Utilities.newCoreException(NLS.bind(Messages.OperationsManager_error_uninstall, (new String[] { feature.getVersionedIdentifier().toString() })), null);
+ }
+ targetSite.remove(feature, pm);
+ } else {
+ // we should do something here
+ String message =
+ NLS.bind(Messages.OperationsManager_error_uninstall, (new String[] { feature.getLabel() }));
+ IStatus status =
+ new Status(
+ IStatus.ERROR,
+ UpdateUtils.getPluginId(),
+ IStatus.OK,
+ message,
+ null);
+ throw new CoreException(status);
+ }
+
+ markProcessed();
+ if (listener != null)
+ listener.afterExecute(this, null);
+
+ restartNeeded = SiteManager.getLocalSite().save() && restartNeeded;
+
+ // notify the model
+ OperationsManager.fireObjectChanged(feature, UNINSTALL);
+
+ return restartNeeded;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UpdateUtils.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UpdateUtils.java
new file mode 100644
index 0000000..6914a0a
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UpdateUtils.java
@@ -0,0 +1,692 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ * James D Miles (IBM Corp.) - bug 191368, Policy URL doesn't support UTF-8 characters
+ *******************************************************************************/
+package org.eclipse.update.internal.operations;
+
+import java.lang.reflect.*;
+import java.net.*;
+import java.util.ArrayList;
+import java.util.Vector;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.core.model.*;
+import org.eclipse.update.internal.core.*;
+import org.eclipse.update.internal.core.URLEncoder;
+import org.eclipse.update.internal.search.*;
+import org.eclipse.update.operations.*;
+import org.eclipse.update.search.*;
+
+
+/**
+ * Helper class for performing update related tasks, queries, etc.
+ * All the methods are static and this class should be a singleton.
+ */
+public class UpdateUtils {
+ public static final String P_UPDATE_POLICY_URL = "updatePolicyURL"; //$NON-NLS-1$
+
+ /**
+ * Private constructor
+ */
+ private UpdateUtils() {
+ }
+
+
+ public static String getPluginId() {
+ return UpdateCore.getPlugin().getBundle().getSymbolicName();
+ }
+
+
+ public static void logException(Throwable e) {
+
+ if (e instanceof InvocationTargetException) {
+ e = ((InvocationTargetException) e).getTargetException();
+ }
+
+ IStatus status = null;
+ if (e instanceof CoreException) {
+ status = ((CoreException) e).getStatus();
+ } else {
+ String message = e.getMessage();
+ if (message == null)
+ message = e.toString();
+ status = new Status(IStatus.ERROR, getPluginId(), IStatus.OK, message, e);
+ }
+ log(status);
+ }
+
+ public static void log(IStatus status) {
+ if (status.getSeverity() != IStatus.INFO) {
+ UpdateCore.getPlugin().getLog().log(status);
+ }
+ }
+
+ public static IFeature[] searchSite(String featureId, IConfiguredSite site, boolean onlyConfigured) throws CoreException {
+ IFeatureReference[] references = null;
+
+ if (onlyConfigured)
+ references = site.getConfiguredFeatures();
+ else
+ references = site.getSite().getFeatureReferences();
+ Vector result = new Vector();
+
+ for (int i = 0; i < references.length; i++) {
+ IFeature feature = references[i].getFeature(null);
+ String id = feature.getVersionedIdentifier().getIdentifier();
+ if (featureId.equals(id)) {
+ result.add(feature);
+ }
+ }
+ return (IFeature[]) result.toArray(new IFeature[result.size()]);
+ }
+
+ public static IFeature[] getInstalledFeatures(IFeature feature) {
+ return getInstalledFeatures(feature, true);
+ }
+
+ /**
+ *
+ * @param feature
+ * @param onlyConfigured
+ * @return IFeature[] with features matching feature ID
+ */
+ public static IFeature[] getInstalledFeatures(IFeature feature, boolean onlyConfigured) {
+ return getInstalledFeatures(feature.getVersionedIdentifier(), onlyConfigured);
+ }
+ /**
+ * @param vid
+ * @param onlyConfigured
+ * @return IFeature[] with features matching feature ID
+ */
+ public static IFeature[] getInstalledFeatures(VersionedIdentifier vid, boolean onlyConfigured) {
+ Vector features = new Vector();
+ try {
+ ILocalSite localSite = SiteManager.getLocalSite();
+ IInstallConfiguration config = localSite.getCurrentConfiguration();
+ IConfiguredSite[] isites = config.getConfiguredSites();
+ String id = vid.getIdentifier();
+
+ for (int i = 0; i < isites.length; i++) {
+ IConfiguredSite isite = isites[i];
+ IFeature[] result = UpdateUtils.searchSite(id, isite, onlyConfigured);
+ for (int j = 0; j < result.length; j++) {
+ IFeature installedFeature = result[j];
+ features.add(installedFeature);
+ }
+ }
+ } catch (CoreException e) {
+ UpdateUtils.logException(e);
+ }
+ return (IFeature[]) features.toArray(new IFeature[features.size()]);
+ }
+
+ /**
+ * @param patch
+ * @return IFeature or null
+ */
+ public static IFeature getPatchedFeature(IFeature patch) {
+ IImport[] imports = patch.getImports();
+ for (int i = 0; i < imports.length; i++) {
+ IImport iimport = imports[i];
+ if (iimport.isPatch()) {
+ VersionedIdentifier patchedVid = iimport
+ .getVersionedIdentifier();
+ // features with matching id
+ IFeature[] features = getInstalledFeatures(patchedVid, false);
+ for (int f = 0; f < features.length; f++) {
+ // check if version match
+ if (patchedVid.equals(features[f].getVersionedIdentifier())) {
+ return features[f];
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public static boolean isPatch(IFeature candidate) {
+ IImport[] imports = candidate.getImports();
+
+ for (int i = 0; i < imports.length; i++) {
+ IImport iimport = imports[i];
+ if (iimport.isPatch()) return true;
+ }
+ return false;
+ }
+
+ public static boolean isPatch(IFeature target, IFeature candidate) {
+ VersionedIdentifier vid = target.getVersionedIdentifier();
+ IImport[] imports = candidate.getImports();
+
+ for (int i = 0; i < imports.length; i++) {
+ IImport iimport = imports[i];
+ if (iimport.isPatch()) {
+ VersionedIdentifier ivid = iimport.getVersionedIdentifier();
+ if (vid.equals(ivid)) {
+ // Bingo.
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public static IInstallConfiguration getBackupConfigurationFor(IFeature feature) {
+ VersionedIdentifier vid = feature.getVersionedIdentifier();
+ String key = "@" + vid.getIdentifier() + "_" + vid.getVersion(); //$NON-NLS-1$ //$NON-NLS-2$
+ try {
+ ILocalSite lsite = SiteManager.getLocalSite();
+ IInstallConfiguration[] configs = lsite.getPreservedConfigurations();
+ for (int i = 0; i < configs.length; i++) {
+ IInstallConfiguration config = configs[i];
+ if (config.getLabel().startsWith(key))
+ return config;
+ }
+ } catch (CoreException e) {
+ }
+ return null;
+ }
+
+
+ public static boolean hasLicense(IFeature feature) {
+ IURLEntry info = feature.getLicense();
+ if (info == null)
+ return false;
+ String licenseTxt = info.getAnnotation();
+ if (licenseTxt == null)
+ return false;
+ return licenseTxt.trim().length() > 0;
+ }
+ public static boolean hasOptionalFeatures(IFeature feature) {
+ try {
+ IIncludedFeatureReference[] irefs = feature.getIncludedFeatureReferences();
+ for (int i = 0; i < irefs.length; i++) {
+ IIncludedFeatureReference iref = irefs[i];
+ if (iref.isOptional())
+ return true;
+ // see if it has optional children
+ IFeature child = getIncludedFeature( feature, iref);
+ if (hasOptionalFeatures(child))
+ return true;
+ }
+ } catch (CoreException e) {
+ }
+ return false;
+ }
+
+ public static IFeature getLocalFeature(
+ IConfiguredSite csite,
+ IFeature feature)
+ throws CoreException {
+ IFeatureReference[] refs = csite.getConfiguredFeatures();
+ for (int i = 0; i < refs.length; i++) {
+ IFeatureReference ref = refs[i];
+ VersionedIdentifier refVid = ref.getVersionedIdentifier();
+ if (feature.getVersionedIdentifier().equals(refVid))
+ return ref.getFeature(null);
+ }
+ return null;
+ }
+
+ public static IConfiguredSite getConfigSite(
+ IFeature feature,
+ IInstallConfiguration config)
+ throws CoreException {
+ IConfiguredSite[] configSites = config.getConfiguredSites();
+ for (int i = 0; i < configSites.length; i++) {
+ IConfiguredSite site = configSites[i];
+ if (site.getSite().equals(feature.getSite())) {
+ return site;
+ }
+ }
+ return null;
+ }
+
+ public static IConfiguredSite getDefaultTargetSite(
+ IInstallConfiguration config,
+ IInstallFeatureOperation pendingChange) {
+ return getDefaultTargetSite(config, pendingChange, true);
+ }
+
+ public static IConfiguredSite getDefaultTargetSite(
+ IInstallConfiguration config,
+ IInstallFeatureOperation pendingChange,
+ boolean checkAffinityFeature) {
+ IFeature oldFeature = pendingChange.getOldFeature();
+ IFeature newFeature = pendingChange.getFeature();
+ if (oldFeature != null) {
+ // We should install into the same site as
+ // the old feature
+ try {
+ return getConfigSite(oldFeature, config);
+ } catch (CoreException e) {
+ logException(e);
+ return null;
+ }
+ }
+
+ // This is a new install. Check if there is
+ // a disabled feature with the same ID
+ String newFeatureID =
+ newFeature.getVersionedIdentifier().getIdentifier();
+ IConfiguredSite sameSite = getSiteWithFeature(config, newFeatureID);
+ if (sameSite != null) {
+ return sameSite;
+ }
+
+ if (checkAffinityFeature) {
+ return getAffinitySite(config, newFeature);
+ }
+ return null;
+ }
+
+ public static IConfiguredSite getAffinitySite(
+ IInstallConfiguration config,
+ IFeature newFeature) {
+ // check if the affinity feature is installed
+ String affinityID = newFeature.getAffinityFeature();
+ if (affinityID != null) {
+ IConfiguredSite affinitySite =
+ getSiteWithFeature(config, affinityID);
+ if (affinitySite != null)
+ return affinitySite;
+ } else {
+ // if this is a patch, collocate with the feature
+ IFeature patchedFeature = getPatchedFeature(newFeature);
+ if (patchedFeature != null)
+ return getSiteWithFeature(config, patchedFeature.getVersionedIdentifier().getIdentifier());
+ }
+ return null;
+ }
+
+ public static IConfiguredSite getSiteWithFeature(
+ IInstallConfiguration config,
+ String featureID) {
+ if (featureID == null)
+ return null;
+ IConfiguredSite[] sites = config.getConfiguredSites();
+ for (int i = 0; i < sites.length; i++) {
+ IConfiguredSite site = sites[i];
+ IFeatureReference[] refs = site.getFeatureReferences();
+ for (int j = 0; j < refs.length; j++) {
+ IFeatureReference ref = refs[j];
+ try {
+ IFeature feature = ref.getFeature(null);
+ if (featureID
+ .equals(
+ feature
+ .getVersionedIdentifier()
+ .getIdentifier())) {
+ // found it
+ return site;
+ }
+ } catch (CoreException e) {
+ logException(e);
+ }
+ }
+ }
+ return null;
+ }
+
+ public static void collectOldFeatures(
+ IFeature feature,
+ IConfiguredSite targetSite,
+ ArrayList result)
+ throws CoreException {
+ IIncludedFeatureReference[] included =
+ feature.getIncludedFeatureReferences();
+ for (int i = 0; i < included.length; i++) {
+ IIncludedFeatureReference iref = included[i];
+
+ IFeature ifeature;
+
+ try {
+ ifeature = iref.getFeature(null);
+ } catch (CoreException e) {
+ if (iref.isOptional())
+ continue;
+ throw e;
+ }
+ // find other features and unconfigure
+ String id = iref.getVersionedIdentifier().getIdentifier();
+ IFeature[] sameIds = UpdateUtils.searchSite(id, targetSite, true);
+ for (int j = 0; j < sameIds.length; j++) {
+ IFeature sameId = sameIds[j];
+ // Ignore self.
+ if (sameId.equals(ifeature))
+ continue;
+ result.add(sameId);
+ }
+ collectOldFeatures(ifeature, targetSite, result);
+ }
+ }
+
+//
+// public static IInstallConfiguration createInstallConfiguration() throws CoreException{
+// try {
+// ILocalSite localSite = SiteManager.getLocalSite();
+// IInstallConfiguration config =
+// localSite.cloneCurrentConfiguration();
+// config.setLabel(Utilities.format(config.getCreationDate()));
+// return config;
+// } catch (CoreException e) {
+// // Let callers handle logging
+// //logException(e);
+// throw e;
+// }
+// }
+
+ public static UpdateSearchRequest createNewUpdatesRequest(IFeature [] features) {
+ return createNewUpdatesRequest(features, true);
+ }
+
+ public static UpdateSearchRequest createNewUpdatesRequest(IFeature [] features, boolean automatic) {
+ UpdateSearchScope scope = new UpdateSearchScope();
+ scope.setUpdateMapURL(UpdateUtils.getUpdateMapURL());
+ UpdatesSearchCategory category = new UpdatesSearchCategory(automatic);
+ if (features!=null)
+ category.setFeatures(features);
+ UpdateSearchRequest searchRequest = new UpdateSearchRequest(category, scope);
+ searchRequest.addFilter(new EnvironmentFilter());
+ searchRequest.addFilter(new BackLevelFilter());
+ return searchRequest;
+ }
+
+ public static boolean isNestedChild(IInstallConfiguration config, IFeature feature) {
+ IConfiguredSite[] csites = config.getConfiguredSites();
+ try {
+ for (int i = 0; csites != null && i < csites.length; i++) {
+ IFeatureReference[] refs = csites[i].getConfiguredFeatures();
+ for (int j = 0; refs != null && j < refs.length; j++) {
+ IFeature parent = refs[j].getFeature(null);
+ IFeatureReference[] children =
+ parent.getIncludedFeatureReferences();
+ for (int k = 0;
+ children != null && k < children.length;
+ k++) {
+ IFeature child = children[k].getFeature(null);
+ if (feature.equals(child))
+ return true;
+ }
+ }
+ }
+ } catch (CoreException e) {
+ // will return false
+ }
+ return false;
+ }
+
+
+ public static boolean hasObsoletePatches(IFeature feature) {
+ // Check all the included features that
+ // are unconfigured, and see if their patch
+ // references are better than the original.
+ try {
+ IFeatureReference[] irefs = feature.getIncludedFeatureReferences();
+ for (int i = 0; i < irefs.length; i++) {
+ IFeatureReference iref = irefs[i];
+ IFeature ifeature = iref.getFeature(null);
+ IConfiguredSite csite = ifeature.getSite().getCurrentConfiguredSite();
+ if (!csite.isConfigured(ifeature)) {
+ if (!isPatchHappy(ifeature))
+ return false;
+ }
+ }
+ } catch (CoreException e) {
+ return false;
+ }
+ // All checks went well
+ return true;
+ }
+
+ public static boolean isPatchHappy(IFeature feature) throws CoreException {
+ // If this is a patch and it includes
+ // another patch and the included patch
+ // is disabled but the feature it was declared
+ // to patch is now newer (and is presumed to
+ // contain the now disabled patch), and
+ // the newer patched feature is enabled,
+ // a 'leap of faith' assumption can be
+ // made:
+
+ // Although the included patch is disabled,
+ // the feature it was designed to patch
+ // is now newer and most likely contains
+ // the equivalent fix and more. Consequently,
+ // we can claim that the status and the error
+ // icon overlay are misleading because
+ // all the right plug-ins are configured.
+ IImport[] imports = feature.getImports();
+ IImport patchReference = null;
+ for (int i = 0; i < imports.length; i++) {
+ IImport iimport = imports[i];
+ if (iimport.isPatch()) {
+ patchReference = iimport;
+ break;
+ }
+ }
+ if (patchReference == null)
+ return false;
+ VersionedIdentifier refVid = patchReference.getVersionedIdentifier();
+
+ // Find the patched feature and
+ IConfiguredSite csite = feature.getSite().getCurrentConfiguredSite();
+ if (csite == null)
+ return false;
+
+ IFeatureReference[] crefs = csite.getConfiguredFeatures();
+ for (int i = 0; i < crefs.length; i++) {
+ IFeatureReference cref = crefs[i];
+ VersionedIdentifier cvid = cref.getVersionedIdentifier();
+ if (cvid.getIdentifier().equals(refVid.getIdentifier())) {
+ // This is the one.
+ if (cvid.getVersion().isGreaterThan(refVid.getVersion())) {
+ // Bingo: we found the referenced feature
+ // and its version is greater -
+ // we can assume that it contains better code
+ // than the patch that referenced the
+ // older version.
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public static URL getUpdateMapURL() {
+ Preferences pref = UpdateCore.getPlugin().getPluginPreferences();
+ String mapFile = pref.getString(UpdateUtils.P_UPDATE_POLICY_URL);
+ if (mapFile!=null && mapFile.length()>0) {
+ try {
+ URL url = new URL(mapFile);
+ URL resolvedURL = URLEncoder.encode(url);
+ return resolvedURL;
+ }
+ catch (MalformedURLException e) {
+ UpdateUtils.logException(e);
+ }
+ }
+ return null;
+ }
+
+ /*
+ * Load the update map using the map URL found in the scope.
+ */
+ public static IStatus loadUpdatePolicy(UpdatePolicy map, URL url, IProgressMonitor monitor) throws CoreException {
+ monitor.subTask(Messages.UpdateSearchRequest_loadingPolicy);
+ try {
+ map.load(url, monitor);
+ monitor.worked(1);
+ }
+ catch (CoreException e) {
+ IStatus status = e.getStatus();
+ if (status == null
+ || status.getCode() != ISite.SITE_ACCESS_EXCEPTION)
+ throw e;
+ monitor.worked(1);
+ return status;
+ }
+ return null;
+ }
+
+ public static void downloadFeatureContent(
+ IConfiguredSite targetSite,
+ IFeature feature,
+ IFeatureReference[] optionalChildren, // null when feature has no optional features
+ IProgressMonitor progress)
+ throws InstallAbortedException, CoreException {
+
+ //DEBUG
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL) {
+ UpdateCore.debug(
+ "Downloading...:" + feature.getURL().toExternalForm()); //$NON-NLS-1$
+ }
+
+ // Get source feature provider and verifier.
+ // Initialize target variables.
+ final IFeatureContentProvider provider =
+ feature.getFeatureContentProvider();
+ IPluginEntry[] targetSitePluginEntries = null;
+
+ // determine list of plugins to install
+ // find the intersection between the plugin entries already contained
+ // on the target site, and plugin entries packaged in source feature
+ IPluginEntry[] sourceFeaturePluginEntries = feature.getPluginEntries();
+
+ boolean featureAlreadyInstalled = false;
+ if (targetSite == null)
+ targetSite = getSiteWithFeature(SiteManager.getLocalSite()
+ .getCurrentConfiguration(), ((Feature) feature)
+ .getFeatureIdentifier());
+ if (targetSite == null) {
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL) {
+ UpdateCore.debug("The site to install in is null"); //$NON-NLS-1$
+ }
+
+ targetSitePluginEntries = new IPluginEntry[0];
+ } else {
+ targetSitePluginEntries = targetSite.getSite().getPluginEntries();
+ featureAlreadyInstalled = UpdateUtils.getLocalFeature(targetSite,feature) != null;
+ }
+ IPluginEntry[] pluginsToInstall =
+ UpdateManagerUtils.diff(
+ sourceFeaturePluginEntries,
+ targetSitePluginEntries);
+ INonPluginEntry[] nonPluginsToInstall = feature.getNonPluginEntries();
+
+ IFeatureReference[] children = feature.getIncludedFeatureReferences();
+ if (optionalChildren != null) {
+ children =
+ UpdateManagerUtils.optionalChildrenToInstall(
+ children,
+ optionalChildren);
+ }
+
+ // make sure we have an InstallMonitor
+ InstallMonitor monitor;
+ if (progress == null)
+ monitor = new InstallMonitor(new NullProgressMonitor());
+ else if (progress instanceof InstallMonitor)
+ monitor = (InstallMonitor) progress;
+ else
+ monitor = new InstallMonitor(progress);
+
+ try {
+ // determine number of monitor tasks
+ // 1 task1 for the feature jar (download)
+ // + n tasks for plugin entries (download for each)
+ // + m tasks per non-plugin data entry (download for each)
+ // TODO custom install handler + 1 task for custom non-plugin entry handling (1 for all combined)
+ // + 3*x tasks for children features (3 subtasks per install)
+ int taskCount =
+ 1
+ + pluginsToInstall.length
+ + nonPluginsToInstall.length
+// + 1
+ + 3 * children.length;
+ monitor.beginTask("", taskCount); //$NON-NLS-1$
+
+ // Download feature archive(s)
+ provider.getFeatureEntryArchiveReferences(monitor);
+ monitorWork(monitor,1);
+
+ // Download plugin archives
+ for (int i = 0; i < pluginsToInstall.length; i++) {
+ provider.getPluginEntryArchiveReferences(pluginsToInstall[i], monitor);
+ monitorWork(monitor,1);
+ }
+
+
+
+ // Download non-plugin archives. Verification handled by optional install handler
+ // Note: do not download non-plugin archives for installed features
+ if (nonPluginsToInstall.length > 0) {
+ // Setup optional install handler
+ InstallHandlerProxy handler = null;
+ if (feature.getInstallHandlerEntry()!=null)
+ handler = new InstallHandlerProxy(
+ IInstallHandler.HANDLER_ACTION_INSTALL,
+ feature,
+ feature.getInstallHandlerEntry(),
+ monitor);
+
+ if (!featureAlreadyInstalled)
+ for (int i = 0; i < nonPluginsToInstall.length; i++) {
+ if (handler==null || handler.acceptNonPluginData(nonPluginsToInstall[i]))
+ provider.getNonPluginEntryArchiveReferences(
+ nonPluginsToInstall[i], monitor);
+ monitorWork(monitor, 1);
+ }
+ else
+ monitorWork(monitor, nonPluginsToInstall.length);
+ }
+
+ // Download child features
+ for (int i = 0; i < children.length; i++) {
+ IFeature childFeature = null;
+ try {
+ childFeature = children[i].getFeature(null);
+ } catch (CoreException e) {
+ UpdateCore.warn(null, e);
+ }
+ if (childFeature != null) {
+ SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, 3);
+ downloadFeatureContent(targetSite, childFeature, optionalChildren, subMonitor);
+ }
+ }
+ } finally {
+ if (monitor != null)
+ monitor.done();
+ }
+ }
+
+ private static void monitorWork(IProgressMonitor monitor, int tick)
+ throws CoreException {
+ if (monitor != null) {
+ monitor.worked(tick);
+ if (monitor.isCanceled()) {
+ String msg = "download cancelled";//Policy.bind("Feature.InstallationCancelled"); //$NON-NLS-1$
+ throw new InstallAbortedException(msg, null);
+ }
+ }
+}
+ public static IFeature getIncludedFeature(IFeature feature, IFeatureReference iref) throws CoreException {
+ IFeature ifeature = null;
+ if (feature.getSite() instanceof ExtendedSite) {
+ ifeature = ((ExtendedSite)feature.getSite()).getLiteFeature(iref.getVersionedIdentifier());
+ }
+ if (ifeature == null) {
+ ifeature = iref.getFeature(new NullProgressMonitor());
+ }
+ return ifeature;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/provisional/SiteOptimizerApplication.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/provisional/SiteOptimizerApplication.java
new file mode 100644
index 0000000..1a979a2
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/provisional/SiteOptimizerApplication.java
@@ -0,0 +1,907 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 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
+ * Chris Aniszczyk (IBM Corp.) - NL-enabled the site optimizer
+ *******************************************************************************/
+package org.eclipse.update.internal.provisional;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.zip.ZipEntry;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPlatformRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.IIncludedFeatureReference;
+import org.eclipse.update.core.IncludedFeatureReference;
+import org.eclipse.update.core.model.DefaultSiteParser;
+import org.eclipse.update.core.model.FeatureModel;
+import org.eclipse.update.core.model.FeatureModelFactory;
+import org.eclipse.update.core.model.FeatureReferenceModel;
+import org.eclipse.update.core.model.ImportModel;
+import org.eclipse.update.core.model.PluginEntryModel;
+import org.eclipse.update.core.model.SiteModel;
+import org.eclipse.update.core.model.URLEntryModel;
+import org.eclipse.update.internal.core.ExtendedSiteURLFactory;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+import org.eclipse.update.internal.jarprocessor.JarProcessor;
+import org.eclipse.update.internal.jarprocessor.JarProcessorExecutor;
+import org.eclipse.update.internal.jarprocessor.Main;
+import org.xml.sax.SAXException;
+
+/**
+ * The application class used to perform update site optimizations.
+ * <p>
+ * This class can only be referenced from <code>org.eclipse.runtime.applications</code>
+ * extension point. It should not be extended or instantiated.
+ * <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>
+ *
+ * @since 3.2
+ */
+public class SiteOptimizerApplication implements IPlatformRunnable {
+ public final static Integer EXIT_ERROR = new Integer(1);
+
+ public final static String JAR_PROCESSOR = "-jarProcessor"; //$NON-NLS-1$
+
+ public final static String DIGEST_BUILDER = "-digestBuilder"; //$NON-NLS-1$
+
+ public final static String INPUT = "input"; //$NON-NLS-1$
+
+ public final static String OUTPUT_DIR = "-outputDir"; //$NON-NLS-1$
+
+ public final static String VERBOSE = "-verbose"; //$NON-NLS-1$
+
+ public final static String JAR_PROCESSOR_PACK = "-pack"; //$NON-NLS-1$
+
+ public final static String JAR_PROCESSOR_UNPACK = "-unpack"; //$NON-NLS-1$
+
+ public final static String JAR_PROCESSOR_REPACK = "-repack"; //$NON-NLS-1$
+
+ public final static String JAR_PROCESSOR_SIGN = "-sign"; //$NON-NLS-1$
+
+ public final static String JAR_PROCESSOR_PROCESS_ALL = "-processAll"; //$NON-NLS-1$
+
+ public final static String SITE_XML = "-siteXML"; //$NON-NLS-1$
+
+ public final static String SITE_ATTRIBUTES_FILE = "siteAttributes.txt"; //$NON-NLS-1$
+
+ public final static String DIGEST_OUTPUT_DIR = "-digestOutputDir"; //$NON-NLS-1$
+
+ /*
+ * private final static String DESCRIPTION = "DESCRIPTION"; private final
+ * static String LICENCE = "LICENCE"; private final static String COPYRIGHT =
+ * "COPYRIGHT"; private final static String FEATURE_LABEL = "FEATURE_LABEL";
+ */
+
+ /**
+ * Parses the command line in the form: [-key [value]]* [inputvalue] If the
+ * last argument does not start with a "-" then it is taken as the input
+ * value and not the value for a preceding -key
+ *
+ * @param args
+ * @return
+ */
+ private Map parseCmdLine(String[] args) {
+ Map cmds = new HashMap();
+ for (int i = 0; i < args.length; i++) {
+ if (i == args.length - 1 && !args[i].startsWith("-")) { //$NON-NLS-1$
+ cmds.put(INPUT, args[i]);
+ } else {
+ String key = args[i];
+ String val = null;
+ if (i < args.length - 2 && !args[i + 1].startsWith("-")) { //$NON-NLS-1$
+ val = args[++i];
+ }
+
+ if (key.startsWith(SITE_XML)) {
+ // System.out.println(val.indexOf(":null"));
+ val = key.substring(key.indexOf("=") + 1); //$NON-NLS-1$
+ // System.out.println(key + ":" + val);
+ cmds.put(SITE_XML, val);
+ } else if (key.startsWith(DIGEST_OUTPUT_DIR)) {
+ val = key.substring(key.indexOf("=") + 1); //$NON-NLS-1$
+ // System.out.println(key + ":" + val);
+ cmds.put(DIGEST_OUTPUT_DIR, val);
+ } else {
+
+ // System.out.println(key + ":" + val);
+ cmds.put(key, val);
+ }
+ }
+ }
+ return cmds;
+ }
+
+ private boolean runJarProcessor(Map params) {
+ Main.Options options = new Main.Options();
+ options.pack = params.containsKey(JAR_PROCESSOR_PACK);
+ options.unpack = params.containsKey(JAR_PROCESSOR_UNPACK);
+ options.repack = params.containsKey(JAR_PROCESSOR_REPACK);
+ options.processAll = params.containsKey(JAR_PROCESSOR_PROCESS_ALL);
+ options.verbose = params.containsKey(VERBOSE);
+ options.signCommand = (String) params.get(JAR_PROCESSOR_SIGN);
+ options.outputDir = (String) params.get(OUTPUT_DIR);
+
+ String problem = null;
+
+ String input = (String) params.get(INPUT);
+ if (input == null)
+ problem = Messages.SiteOptimizer_inputNotSpecified;
+ else {
+ File inputFile = new File(input);
+ if (inputFile.exists())
+ options.input = inputFile;
+ else
+ problem = NLS.bind(Messages.SiteOptimizer_inputFileNotFound,
+ new String[] { input });
+ }
+
+ if (options.unpack) {
+ if (!JarProcessor.canPerformUnpack()) {
+ problem = Messages.JarProcessor_unpackNotFound;
+ } else if (options.pack || options.repack
+ || options.signCommand != null) {
+ problem = Messages.JarProcessor_noPackUnpack;
+ }
+ } else if ((options.pack || options.repack)
+ && !JarProcessor.canPerformPack()) {
+ problem = Messages.JarProcessor_packNotFound;
+ }
+
+ if (problem != null) {
+ System.out.println(problem);
+ return false;
+ }
+
+ new JarProcessorExecutor().runJarProcessor(options);
+ return true;
+ }
+
+ private boolean runDigestBuilder(Map params) {
+
+ List featureList = getFeatureList(params);
+
+ if ((featureList == null) || featureList.isEmpty()) {
+ System.out.println("no features to process"); //$NON-NLS-1$
+ return false;
+ }
+ Map perFeatureLocales = new HashMap();
+ Map availableLocales = getAvailableLocales(featureList,
+ perFeatureLocales);
+ try {
+ openInputStremas(availableLocales);
+ } catch (IOException e1) {
+ e1.printStackTrace();
+ System.out.println("Can not create file in output direcotry"); //$NON-NLS-1$
+ return false;
+ }
+
+ for(int i = 0; i < featureList.size(); i++) {
+
+ String featureJarFileName = (String) featureList.get(i);
+
+ if (featureJarFileName.endsWith("jar")) { //$NON-NLS-1$
+ System.out.println("Processing... " + featureJarFileName); //$NON-NLS-1$
+ } else {
+ System.out.println("Skipping... " + featureJarFileName); //$NON-NLS-1$
+ continue;
+ }
+
+ JarFile featureJar = null;
+ try {
+ featureJar = new JarFile(featureJarFileName);
+ } catch (IOException e) {
+ System.out.println("Problem with opening jar: " //$NON-NLS-1$
+ + featureJarFileName);
+ e.printStackTrace();
+ return false;
+ }
+ FeatureModelFactory fmf = new FeatureModelFactory();
+
+ try {
+ ZipEntry featureXMLEntry = featureJar.getEntry("feature.xml"); //$NON-NLS-1$
+ Map featureProperties = loadProperties(featureJar,
+ featureJarFileName, perFeatureLocales);
+
+ FeatureModel featureModel = fmf.parseFeature(featureJar
+ .getInputStream(featureXMLEntry));
+
+ featureList = addFeaturesToList( (String) params.get(SITE_XML), featureList, featureModel.getFeatureIncluded(), availableLocales, perFeatureLocales);
+
+ Iterator availableLocalesIterator = availableLocales.values()
+ .iterator();
+ while (availableLocalesIterator.hasNext()) {
+ ((AvailableLocale) availableLocalesIterator.next())
+ .writeFeatureDigests(featureModel,
+ featureProperties);
+ }
+
+ } catch (SAXException e) {
+ e.printStackTrace();
+ return false;
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ } catch (CoreException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ Iterator availableLocalesIterator = availableLocales.values()
+ .iterator();
+ String outputDirectory = (String) params.get(DIGEST_OUTPUT_DIR);
+
+ outputDirectory = outputDirectory.substring(outputDirectory
+ .indexOf("=") + 1); //$NON-NLS-1$
+ if (!outputDirectory.endsWith(File.separator)) {
+ outputDirectory = outputDirectory + File.separator;
+ }
+ while (availableLocalesIterator.hasNext()) {
+ try {
+ ((AvailableLocale) availableLocalesIterator.next())
+ .finishDigest(outputDirectory);
+ } catch (IOException e) {
+ System.out.println("Can not write in digest output directory: " //$NON-NLS-1$
+ + outputDirectory);
+ e.printStackTrace();
+ return false;
+ }
+ }
+ System.out.println("Done"); //$NON-NLS-1$
+ return true;
+ }
+
+ private List addFeaturesToList( String siteXML, List featureList, IIncludedFeatureReference[] iIncludedFeatureReferences, Map availableLocales, Map perFeatureLocales ) throws CoreException {
+
+ String directoryName = (new File(siteXML)).getParent();
+ if (!directoryName.endsWith(File.separator)) {
+ directoryName = directoryName + File.separator;
+ }
+ directoryName = directoryName + "features" + File.separator; //$NON-NLS-1$
+
+ for (int i = 0; i < iIncludedFeatureReferences.length; i++) {
+ String featureURL = directoryName + iIncludedFeatureReferences[i].getVersionedIdentifier() + ".jar"; //$NON-NLS-1$
+ if (!(isFeatureAlreadyInList(featureList, featureURL))) {
+ try {
+ System.out.println("Extracting locales from included feature " + featureURL); //$NON-NLS-1$
+ processLocalesInJar(availableLocales, featureURL, perFeatureLocales, true);
+ } catch (IOException e) {
+ if (iIncludedFeatureReferences[i].isOptional())
+ continue;
+ System.out.println("Error while extracting locales from included feature " + featureURL);//$NON-NLS-1$
+ e.printStackTrace();
+ throw new CoreException( new Status( IStatus.ERROR, UpdateCore.getPlugin().getBundle().getSymbolicName(), IStatus.OK, "Error while extracting locales from included feature " + featureURL, e)); //$NON-NLS-1$
+ }
+ featureList.add(featureURL);
+ }
+ }
+
+ return featureList;
+ }
+
+ private boolean isFeatureAlreadyInList(List featureList, String featureURL) {
+ for (int i = 0; i < featureList.size(); i++) {
+ String currentFeatureURL = (String)featureList.get(i);
+ if (currentFeatureURL.equals(featureURL)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private Map loadProperties(JarFile featureJar, String featureJarFileName,
+ Map perFeatureLocales) {
+ // System.out.println(
+ // ((List)perFeatureLocales.get(featureJarFileName)).size());
+ Iterator it = ((List) perFeatureLocales.get(featureJarFileName))
+ .iterator();
+ Map result = new HashMap();
+ while (it.hasNext()) {
+ String propertyFileName = (String) it.next();
+
+ ZipEntry featurePropertiesEntry = featureJar
+ .getEntry(propertyFileName);
+ Properties featureProperties = new Properties();
+ if (featurePropertiesEntry != null) {
+ try {
+ featureProperties.load(featureJar
+ .getInputStream(featurePropertiesEntry));
+ String localeString = null;
+ if (propertyFileName.endsWith("feature.properties")) { //$NON-NLS-1$
+ localeString = ""; //$NON-NLS-1$
+ } else {
+ localeString = propertyFileName.substring(8,
+ propertyFileName.indexOf('.'));
+ }
+ result.put(localeString, featureProperties);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return result;
+ }
+
+ private void openInputStremas(Map availableLocales) throws IOException {
+ Iterator locales = availableLocales.values().iterator();
+ while (locales.hasNext()) {
+ AvailableLocale availableLocale = (AvailableLocale) locales.next();
+ availableLocale.openLocalizedOutputStream();
+ }
+ }
+
+ private Map getAvailableLocales(List featureList, Map perFeatureLocales) {
+ Iterator features = featureList.iterator();
+ Map locales = new HashMap();
+ while (features.hasNext()) {
+ String feature = (String) features.next();
+ try {
+ System.out.println("Extracting locales from " + feature); //$NON-NLS-1$
+ processLocalesInJar(locales, feature, perFeatureLocales, false);
+ } catch (IOException e) {
+ System.out.println("Error while extracting locales from " //$NON-NLS-1$
+ + feature);
+ e.printStackTrace();
+ return null;
+ }
+ }
+ return locales;
+ }
+
+ private void processLocalesInJar(Map locales, String feature,
+ Map perFeatureLocales, boolean ignoreNewLocales) throws IOException {
+
+ JarFile jar = new JarFile(feature);
+ // System.out.println(feature);
+ Enumeration files = jar.entries();
+
+ List localesTemp = new ArrayList();
+ perFeatureLocales.put(feature, localesTemp);
+
+ while (files.hasMoreElements()) {
+ ZipEntry file = (ZipEntry) files.nextElement();
+ String localeString = null;
+ String name = file.getName();
+ // System.out.println("processLocalesInJar:"+name);
+ if (name.startsWith("feature") && name.endsWith(".properties")) { //$NON-NLS-1$ //$NON-NLS-2$
+ // System.out.println(name);
+ localesTemp.add(name);
+ // System.out.println(name);
+ if (name.endsWith("feature.properties")) { //$NON-NLS-1$
+ localeString = ""; //$NON-NLS-1$
+ } else {
+ localeString = name.substring(8, name.indexOf('.'));
+ }
+ // System.out.println(name +"::::\"" + localeString + "\"");
+ if ( !ignoreNewLocales && !locales.containsKey(localeString)) {
+ locales.put(localeString, new AvailableLocale(localeString));
+ }
+ if (locales.containsKey(localeString)) {
+ AvailableLocale currentLocale = (AvailableLocale) locales.get(localeString);
+ currentLocale.addFeatures(feature);
+ }
+ }
+ }
+
+ }
+
+ private List getFeatureList(Map params) {
+ if (params.containsKey(SITE_XML)
+ && (fileExists((String) params.get(SITE_XML)))) {
+ return getFeatureListFromSiteXML((String) params.get(SITE_XML));
+ } else if (params.containsKey(INPUT)
+ && isDirectory((String) params
+ .get(SiteOptimizerApplication.INPUT))) {
+ return getFeatureListFromDirectory((String) params.get(INPUT));
+ }
+ return null;
+ }
+
+ private boolean fileExists(String fileName) {
+ // System.out.println("fileExists:"+fileName);
+ File file = new File(fileName);
+ if ((file != null) && file.exists())
+ return true;
+ return false;
+ }
+
+ private List getFeatureListFromDirectory(String directoryName) {
+ List featuresURLs = new ArrayList();
+ File directory = new File(directoryName);
+ String[] featureJarFileNames = directory.list();
+ for (int i = 0; i < featureJarFileNames.length; i++) {
+ featuresURLs.add(directoryName + File.separator
+ + featureJarFileNames[i]);
+ }
+ return featuresURLs;
+ }
+
+ private boolean isDirectory(String fileName) {
+
+ File directory = new File(fileName);
+ if ((directory != null) && directory.exists()
+ && directory.isDirectory())
+ return true;
+ return false;
+ }
+
+ private List getFeatureListFromSiteXML(String siteXML) {
+
+ List featuresURLs = new ArrayList();
+ String directoryName = (new File(siteXML)).getParent();
+ if (!directoryName.endsWith(File.separator)) {
+ directoryName = directoryName + File.separator;
+ }
+
+ DefaultSiteParser siteParser = new DefaultSiteParser();
+ siteParser.init(new ExtendedSiteURLFactory());
+
+ try {
+ SiteModel site = siteParser.parse(new FileInputStream(siteXML));
+ if(site.getFeatureReferenceModels().length > 0) {
+ site.getFeatureReferenceModels()[0].getURLString();
+ FeatureReferenceModel[] featureReferenceModel = site
+ .getFeatureReferenceModels();
+ for (int i = 0; i < featureReferenceModel.length; i++) {
+ featuresURLs.add(directoryName
+ + featureReferenceModel[i].getURLString());
+ }
+ }
+ return featuresURLs;
+ } catch (FileNotFoundException e) {
+ System.out.println("File not found: " + e.getMessage()); //$NON-NLS-1$
+ e.printStackTrace();
+ } catch (SAXException e) {
+ System.out.println("Parsing problem: " + e.getMessage()); //$NON-NLS-1$
+ e.printStackTrace();
+ } catch (IOException e) {
+ System.out.println("Problem while parsing: " + e.getMessage()); //$NON-NLS-1$
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.runtime.IPlatformRunnable#run(java.lang.Object)
+ */
+ public Object run(Object args) throws Exception {
+ Platform.endSplash();
+ if (args == null)
+ return EXIT_ERROR;
+ if (args instanceof String[]) {
+ Map params = parseCmdLine((String[]) args);
+ if (params.containsKey(JAR_PROCESSOR)) {
+ if (!runJarProcessor(params))
+ return EXIT_ERROR;
+ }
+
+ if (params.containsKey(DIGEST_BUILDER)) {
+ if (!runDigestBuilder(params))
+ return EXIT_ERROR;
+ }
+ }
+ return IPlatformRunnable.EXIT_OK;
+ }
+
+ private class AvailableLocale {
+
+ private String PREFIX = "temp"; //$NON-NLS-1$
+
+ private String locale;
+
+ private Map /* VersionedIdentifier */features = new HashMap();
+
+ private PrintWriter localizedPrintWriter;
+
+ private File tempDigestDirectory;
+
+ public void finishDigest(String outputDirectory) throws IOException {
+ localizedPrintWriter.println("</digest>"); //$NON-NLS-1$
+ if (localizedPrintWriter != null) {
+ localizedPrintWriter.close();
+ }
+
+ File digest = new File(outputDirectory + File.separator + "digest" //$NON-NLS-1$
+ + (locale == null || locale.equals("") ? "" : "_"+locale) + ".zip"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ System.out.println(digest.getAbsolutePath());
+ System.out.println(digest.getName());
+ if (digest.exists()) {
+ digest.delete();
+ }
+ digest.createNewFile();
+ OutputStream os = new FileOutputStream(digest);
+ JarOutputStream jos = new JarOutputStream(os);
+ jos.putNextEntry(new ZipEntry("digest.xml")); //$NON-NLS-1$
+ InputStream is = new FileInputStream(tempDigestDirectory);
+ byte[] b = new byte[4096];
+ int bytesRead = 0;
+ do {
+ bytesRead = is.read(b);
+ if (bytesRead > 0) {
+ jos.write(b, 0, bytesRead);
+ }
+ } while (bytesRead > 0);
+
+ jos.closeEntry();
+ jos.close();
+ os.close();
+ is.close();
+ tempDigestDirectory.delete();
+
+ }
+
+ public AvailableLocale(String locale) {
+ this.locale = locale;
+ }
+
+ public void addFeatures(String feature) {
+ features.put(feature, feature);
+ }
+
+ public void openLocalizedOutputStream() throws IOException {
+ tempDigestDirectory = File.createTempFile(PREFIX, null);
+ FileOutputStream fstream = new FileOutputStream(tempDigestDirectory);
+ localizedPrintWriter = new PrintWriter(new OutputStreamWriter(fstream, "UTF-8")); //$NON-NLS-1$
+ localizedPrintWriter
+ .println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n <digest>"); //$NON-NLS-1$
+ tempDigestDirectory.deleteOnExit();
+ }
+
+ public int hashCode() {
+ return locale.hashCode();
+ }
+
+ public boolean equals(Object obj) {
+
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final AvailableLocale other = (AvailableLocale) obj;
+ if (locale == null) {
+ if (other.locale != null)
+ return false;
+ } else if (!locale.equals(other.locale))
+ return false;
+ return true;
+ }
+
+ public void writeFeatureDigests(FeatureModel featureModel,
+ Map featureProperties) {
+
+ if (this.locale.equals("")) { //$NON-NLS-1$
+ writeFeatureDigest(localizedPrintWriter, featureModel,
+ (Properties) featureProperties.get("")); //$NON-NLS-1$
+ return;
+ }
+ Properties temp = new Properties();
+ if (locale.indexOf("_") < 0) { //$NON-NLS-1$
+ temp = combineProperties(
+ (Properties) featureProperties.get(""), //$NON-NLS-1$
+ (Properties) featureProperties.get(locale), null);
+ writeFeatureDigest(localizedPrintWriter, featureModel, temp);
+ } else {
+ temp = combineProperties(
+ (Properties) featureProperties.get(""), //$NON-NLS-1$
+ (Properties) featureProperties.get(locale.substring(0, locale.indexOf("_"))), //$NON-NLS-1$
+ (Properties) featureProperties.get(locale) );
+ writeFeatureDigest(localizedPrintWriter, featureModel, temp);
+ }
+
+ }
+
+ /**
+ * @param defaults Should be lang_country
+ * @param secondary Should be lang
+ * @param preferred Should be default
+ * @return
+ */
+
+ private Properties combineProperties(Properties defaults,
+ Properties secondary, Properties preferred) {
+ return new CombinedProperties(preferred, secondary, defaults);
+
+ }
+
+ }
+
+ public static void writeFeatureDigest(PrintWriter digest,
+ FeatureModel featureModel, Properties featureProperties) {
+
+ String label = null;
+ String provider = null;
+ String description = null;
+ String license = null;
+ String copyright = null;
+
+ if ((featureProperties != null)
+ && featureModel.getLabel().startsWith("%")) { //$NON-NLS-1$
+ label = featureProperties.getProperty(featureModel.getLabel()
+ .substring(1));
+ } else {
+ label = featureModel.getLabel();
+ }
+ if ((featureProperties != null)
+ && (featureModel.getDescriptionModel() != null)
+ && (featureModel.getDescriptionModel().getAnnotation() != null)
+ && featureModel.getDescriptionModel().getAnnotation()
+ .startsWith("%")) { //$NON-NLS-1$
+ // System.out.println(featureProperties.getProperty(featureModel.getDescriptionModel().getAnnotation().substring(1)));
+ description = featureProperties.getProperty(featureModel
+ .getDescriptionModel().getAnnotation().substring(1));
+ } else {
+ URLEntryModel descriptionModel = featureModel.getDescriptionModel();
+ if( descriptionModel == null )
+ description = "";
+ else
+ description = descriptionModel.getAnnotation();
+ }
+ String pvalue = featureModel.getProvider();
+ if ((featureProperties != null)
+ && pvalue!=null && pvalue.startsWith("%")) { //$NON-NLS-1$
+ provider = featureProperties.getProperty(featureModel.getProvider()
+ .substring(1));
+ } else {
+ provider = pvalue;
+ }
+ if (provider==null) provider = "";
+
+ if (((featureProperties != null) && featureModel.getCopyrightModel() != null)
+ && featureModel.getCopyrightModel().getAnnotation().startsWith(
+ "%")) { //$NON-NLS-1$
+ copyright = featureProperties.getProperty(featureModel
+ .getCopyrightModel().getAnnotation().substring(1));
+ } else {
+ if (featureModel.getCopyrightModel() != null) {
+ copyright = featureModel.getCopyrightModel().getAnnotation();
+ } else {
+ copyright = null;
+ }
+ }
+
+ if ((featureProperties != null)
+ && (featureModel.getLicenseModel() != null)
+ && featureModel.getLicenseModel().getAnnotation().startsWith(
+ "%")) { //$NON-NLS-1$
+ license = featureProperties.getProperty(featureModel
+ .getLicenseModel().getAnnotation().substring(1));
+ } else {
+ license = featureModel.getLicenseModel().getAnnotation();
+ }
+
+ digest.print("<feature "); //$NON-NLS-1$
+ digest.print("label=\"" + getUTF8String(label) + "\" "); //$NON-NLS-1$//$NON-NLS-2$
+ digest.print("provider-name=\"" + getUTF8String(provider) + "\" "); //$NON-NLS-1$ //$NON-NLS-2$
+ digest.print("id=\"" + featureModel.getFeatureIdentifier() + "\" "); //$NON-NLS-1$//$NON-NLS-2$
+ digest.print("version=\"" + featureModel.getFeatureVersion() + "\" "); //$NON-NLS-1$ //$NON-NLS-2$
+ if (featureModel.getOS() != null)
+ digest.print("os=\"" + featureModel.getOS() + "\" "); //$NON-NLS-1$//$NON-NLS-2$
+ if (featureModel.getNL() != null)
+ digest.print("nl=\"" + featureModel.getNL() + "\" "); //$NON-NLS-1$//$NON-NLS-2$
+ if (featureModel.getWS() != null)
+ digest.print("ws=\"" + featureModel.getWS() + "\" "); //$NON-NLS-1$ //$NON-NLS-2$
+ if (featureModel.getOSArch() != null)
+ digest.print("arch=\"" + featureModel.getOSArch() + "\" "); //$NON-NLS-1$//$NON-NLS-2$
+ if (featureModel.isExclusive())
+ digest.print("exclusive=\"" + featureModel.isExclusive() + "\" "); //$NON-NLS-1$//$NON-NLS-2$
+
+ if (((featureModel.getImportModels() == null) || (featureModel
+ .getImportModels().length == 0))
+ && ((featureModel.getDescriptionModel() == null)
+ || (featureModel.getDescriptionModel().getAnnotation() == null) || (featureModel
+ .getDescriptionModel().getAnnotation().trim().length() == 0))
+ && ((featureModel.getCopyrightModel() == null)
+ || (featureModel.getCopyrightModel().getAnnotation() == null) || (featureModel
+ .getCopyrightModel().getAnnotation().trim().length() == 0))
+ && ((featureModel.getLicenseModel() == null)
+ || (featureModel.getLicenseModel().getAnnotation() == null) || (featureModel
+ .getLicenseModel().getAnnotation().trim().length() == 0))
+ && ((featureModel.getFeatureIncluded() == null) || (featureModel
+ .getFeatureIncluded().length == 0))){
+ digest.println("/> "); //$NON-NLS-1$
+ } else {
+ digest.println("> "); //$NON-NLS-1$
+ if (featureModel.getImportModels().length > 0) {
+
+ digest.println("\t<requires> "); //$NON-NLS-1$
+ ImportModel[] imports = featureModel.getImportModels();
+ for (int j = 0; j < imports.length; j++) {
+ digest.print("\t\t<import "); //$NON-NLS-1$
+ if (imports[j].isFeatureImport()) {
+ digest.print("feature=\""); //$NON-NLS-1$
+ } else {
+ digest.print("plugin=\""); //$NON-NLS-1$
+ }
+ digest.print(imports[j].getIdentifier() + "\" "); //$NON-NLS-1$
+ digest.print("version=\""); //$NON-NLS-1$
+ digest.print(imports[j].getVersion() + "\" "); //$NON-NLS-1$
+ digest.print("match=\""); //$NON-NLS-1$
+ digest.print(imports[j].getMatchingRuleName() + "\" "); //$NON-NLS-1$
+ if (imports[j].isPatch()) {
+ digest.print("patch=\"true\" "); //$NON-NLS-1$
+ }
+ digest.println(" />"); //$NON-NLS-1$
+ }
+
+ digest.println("\t</requires>"); //$NON-NLS-1$
+
+ }
+
+ if ((featureModel.getDescriptionModel() != null)
+ && (featureModel.getDescriptionModel().getAnnotation() != null)
+ && (featureModel.getDescriptionModel().getAnnotation()
+ .trim().length() != 0)) {
+ digest.println("\t<description>"); //$NON-NLS-1$
+ digest.println("\t\t" + UpdateManagerUtils.getWritableXMLString(description)); //$NON-NLS-1$
+ digest.println("\t</description>"); //$NON-NLS-1$
+ }
+
+ if (featureModel.getCopyrightModel() != null) {
+ if (featureModel.getCopyrightModel().getAnnotation() != null) {
+ // if
+ // (featureModel.getDescriptionModel().getAnnotation().length()
+ // != 0) {
+ digest.println("\t<copyright>"); //$NON-NLS-1$
+ digest.println("\t\t" + UpdateManagerUtils.getWritableXMLString(copyright)); //$NON-NLS-1$
+ digest.println("\t</copyright>"); //$NON-NLS-1$
+ // }
+ }
+ }
+
+ if ((featureModel.getLicenseModel() != null)
+ && (featureModel.getLicenseModel().getAnnotation() != null)
+ && (featureModel.getLicenseModel().getAnnotation()
+ .trim().length() != 0)) {
+ digest.println("\t<license>"); //$NON-NLS-1$
+ digest.println("\t\t" + UpdateManagerUtils.getWritableXMLString(license)); //$NON-NLS-1$
+ digest.println("\t</license>"); //$NON-NLS-1$
+ }
+
+ PluginEntryModel[] plugins = featureModel.getPluginEntryModels();
+ if ((plugins != null) && (plugins.length != 0)) {
+ for (int i = 0; i < plugins.length; i++) {
+ digest.print("\t<plugin "); //$NON-NLS-1$
+ digest.print("id=\"" + plugins[i].getPluginIdentifier() //$NON-NLS-1$
+ + "\" "); //$NON-NLS-1$
+ digest.print("version=\"" + plugins[i].getPluginVersion() //$NON-NLS-1$
+ + "\" "); //$NON-NLS-1$
+ if (plugins[i].getOS() != null)
+ digest.print("os=\"" + plugins[i].getOS() + "\" "); //$NON-NLS-1$//$NON-NLS-2$
+ if (plugins[i].getNL() != null)
+ digest.print("nl=\"" + plugins[i].getNL() + "\" "); //$NON-NLS-1$ //$NON-NLS-2$
+ if (plugins[i].getWS() != null)
+ digest.print("ws=\"" + plugins[i].getWS() + "\" "); //$NON-NLS-1$//$NON-NLS-2$
+ if (plugins[i].getOSArch() != null)
+ digest
+ .print("arch=\"" + plugins[i].getOSArch() //$NON-NLS-1$
+ + "\" "); //$NON-NLS-1$
+ if (plugins[i].getDownloadSize() > 0)
+ digest.print("download-size=\"" //$NON-NLS-1$
+ + plugins[i].getDownloadSize() + "\" "); //$NON-NLS-1$
+ if (plugins[i].getInstallSize() > 0)
+ digest.print("install-size=\"" //$NON-NLS-1$
+ + plugins[i].getInstallSize() + "\" "); //$NON-NLS-1$
+ if (!plugins[i].isUnpack())
+ digest.print("unpack=\"" + plugins[i].isUnpack() //$NON-NLS-1$
+ + "\" "); //$NON-NLS-1$
+
+ digest.println("/> "); //$NON-NLS-1$
+ }
+ }
+
+ IIncludedFeatureReference[] includedFeatures = featureModel.getFeatureIncluded();
+
+ if ((includedFeatures != null) && (includedFeatures.length != 0)) {
+ for (int i = 0; i < includedFeatures.length; i++) {
+ try {
+ digest.print("\t<includes "); //$NON-NLS-1$
+
+ digest.print("id=\"" + includedFeatures[i].getVersionedIdentifier().getIdentifier() + "\" "); //$NON-NLS-1$ //$NON-NLS-2$
+ digest.print("version=\"" + includedFeatures[i].getVersionedIdentifier().getVersion() + "\" "); //$NON-NLS-1$ //$NON-NLS-2$
+ if (includedFeatures[i].getOS() != null)
+ digest.print("os=\"" + includedFeatures[i].getOS() + "\" "); //$NON-NLS-1$//$NON-NLS-2$
+ if (includedFeatures[i].getNL() != null)
+ digest.print("nl=\"" + includedFeatures[i].getNL() + "\" "); //$NON-NLS-1$ //$NON-NLS-2$
+ if (includedFeatures[i].getWS() != null)
+ digest.print("ws=\"" + includedFeatures[i].getWS() + "\" "); //$NON-NLS-1$//$NON-NLS-2$
+ if (includedFeatures[i].getOSArch() != null)
+ digest.print("arch=\"" + includedFeatures[i].getOSArch() + "\" "); //$NON-NLS-1$ //$NON-NLS-2$
+ if ( (includedFeatures[i] instanceof IncludedFeatureReference) && (((IncludedFeatureReference)includedFeatures[i]).getLabel() != null))
+ digest.print("name=\"" + includedFeatures[i].getName() + "\" "); //$NON-NLS-1$ //$NON-NLS-2$
+ if (includedFeatures[i].isOptional())
+ digest.print("optional=\"true\" "); //$NON-NLS-1$
+ digest.print("search-location=\"" + includedFeatures[i].getSearchLocation() + "\" "); //$NON-NLS-1$ //$NON-NLS-2$
+
+ digest.println("/> "); //$NON-NLS-1$
+ } catch (CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ digest.println("</feature>"); //$NON-NLS-1$
+ }
+ }
+
+ private class CombinedProperties extends Properties {
+
+ private Properties properties1;
+
+ private Properties properties2;
+
+ private Properties properties3;
+
+ /**
+ * @param preferred preferred, such as lang_country
+ * @param secondary secondary, such as lang
+ * @param defaults default,
+ */
+ public CombinedProperties(Properties preferred,
+ Properties secondary, Properties defaults) {
+ this.properties1 = preferred;
+ this.properties2 = secondary;
+ this.properties3 = defaults;
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public String getProperty(String key) {
+ String result = null;
+ if (properties3 != null && properties3.containsKey(key))
+ result = properties3.getProperty(key);
+ if (properties2 != null && properties2.containsKey(key))
+ result = properties2.getProperty(key);
+ if (properties1 != null && properties1.containsKey(key))
+ result = properties1.getProperty(key);
+ return result;
+ }
+
+ }
+
+ public static final String getUTF8String(String s) {
+ if(s == null)
+ return "";
+ return UpdateManagerUtils.getWritableXMLString(s);
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/BaseSearchCategory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/BaseSearchCategory.java
new file mode 100644
index 0000000..0ee1501
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/BaseSearchCategory.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.search;
+
+import org.eclipse.update.search.*;
+
+public abstract class BaseSearchCategory implements IUpdateSearchCategory {
+ private String id;
+
+ protected BaseSearchCategory(String id) {
+ setId(id);
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ if (this.id==null)
+ this.id = id;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/OptionalFeatureSearchCategory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/OptionalFeatureSearchCategory.java
new file mode 100644
index 0000000..fa463d0
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/OptionalFeatureSearchCategory.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.search;
+
+import java.net.*;
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.search.*;
+
+/**
+ * Searches for optional features
+ */
+public class OptionalFeatureSearchCategory extends BaseSearchCategory {
+ private IUpdateSearchQuery[] queries;
+ private ArrayList vids;
+ private static final String CATEGORY_ID =
+ "org.eclipse.update.core.unified-search"; //$NON-NLS-1$
+
+ private class OptionalQuery implements IUpdateSearchQuery {
+ public void run(
+ ISite site,
+ String[] categoriesToSkip,
+ IUpdateSearchFilter filter,
+ IUpdateSearchResultCollector collector,
+ IProgressMonitor monitor) {
+
+ monitor.beginTask("", vids.size()); //$NON-NLS-1$
+ for (int i = 0; i < vids.size(); i++) {
+ VersionedIdentifier vid = (VersionedIdentifier) vids.get(i);
+ monitor.subTask(vid.toString());
+ IFeature feature =
+ createFeature(
+ site,
+ vid,
+ new SubProgressMonitor(monitor, 1));
+ if (feature!=null && filter.accept(feature))
+ collector.accept(feature);
+ }
+ }
+
+ private IFeature createFeature(
+ ISite site,
+ VersionedIdentifier vid,
+ IProgressMonitor monitor) {
+ try {
+ URL siteURL = site.getURL();
+ //TODO This assumption stands only in the default case
+ // In general, feature archive URL may be mapped on site.
+ // Also, feature type may be something else (not packaged).
+ // We may need additional information (not only id and version)
+ // in order to create a feature on a site.
+ String relative = vid.toString();
+ URL featureURL = new URL(siteURL, "features/" + relative+".jar"); //$NON-NLS-1$ //$NON-NLS-2$
+ return site.createFeature(
+ "org.eclipse.update.core.packaged", //$NON-NLS-1$
+ featureURL,
+ monitor);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.internal.ui.search.ISearchQuery#getSearchSite()
+ */
+ public IQueryUpdateSiteAdapter getQuerySearchSite() {
+ return null;
+ }
+ }
+
+ public void addVersionedIdentifier(VersionedIdentifier vid) {
+ vids.add(vid);
+ }
+
+ public void clear() {
+ vids.clear();
+ }
+
+ public OptionalFeatureSearchCategory() {
+ super(CATEGORY_ID);
+ vids = new ArrayList();
+ queries = new IUpdateSearchQuery[] { new OptionalQuery()};
+ }
+
+ public IUpdateSearchQuery[] getQueries() {
+ return queries;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/QueryUpdateSiteAdapter.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/QueryUpdateSiteAdapter.java
new file mode 100644
index 0000000..e30d391
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/QueryUpdateSiteAdapter.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.search;
+
+import java.net.*;
+
+import org.eclipse.update.search.*;
+
+public class QueryUpdateSiteAdapter extends UpdateSiteAdapter implements IQueryUpdateSiteAdapter {
+ private String mappingId;
+
+ public QueryUpdateSiteAdapter(String label, URL url, String mappingId) {
+ super(label, url);
+ this.mappingId = mappingId;
+ }
+
+ public String getMappingId() {
+ return mappingId;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/SiteSearchCategory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/SiteSearchCategory.java
new file mode 100644
index 0000000..78bd7af
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/SiteSearchCategory.java
@@ -0,0 +1,249 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ * James D Miles (IBM Corp.) - bug 181375, ArrayIndexOutOfBoundsException in SiteSearchCategory$Query
+ * James D Miles (IBM Corp.) - bug 191783, NullPointerException in FeatureDownloader
+ *******************************************************************************/
+package org.eclipse.update.internal.search;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.update.core.ICategory;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.ISiteFeatureReference;
+import org.eclipse.update.internal.core.ExtendedSite;
+import org.eclipse.update.internal.core.LiteFeature;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.search.IQueryUpdateSiteAdapter;
+import org.eclipse.update.search.IUpdateSearchFilter;
+import org.eclipse.update.search.IUpdateSearchQuery;
+import org.eclipse.update.search.IUpdateSearchResultCollector;
+
+/**
+ * Searches an update site
+ */
+public class SiteSearchCategory extends BaseSearchCategory {
+ private IUpdateSearchQuery[] queries;
+ private boolean liteFeaturesAreOK;
+ private static final String CATEGORY_ID =
+ "org.eclipse.update.core.unified-search"; //$NON-NLS-1$
+
+ private static class Query implements IUpdateSearchQuery {
+
+ private boolean liteFeaturesAreOK;
+
+
+ public Query() {
+ liteFeaturesAreOK = false;
+ }
+
+ public Query(boolean liteFeaturesAreOK) {
+ this.liteFeaturesAreOK = liteFeaturesAreOK;
+ }
+
+ public void setLiteFeaturesAreOK(boolean liteFeaturesAreOK) {
+ this.liteFeaturesAreOK = liteFeaturesAreOK;
+ }
+
+ public void run(
+ ISite site,
+ String[] categoriesToSkip,
+ IUpdateSearchFilter filter,
+ IUpdateSearchResultCollector collector,
+ IProgressMonitor monitor) {
+
+ ISiteFeatureReference[] refs = site.getFeatureReferences();
+ HashSet ignores = new HashSet();
+ Map liteFeatures = new HashMap();
+
+ if (categoriesToSkip != null) {
+ for (int i = 0; i < categoriesToSkip.length; i++) {
+ ignores.add(categoriesToSkip[i]);
+ }
+ }
+ List siteFeatureReferences = new ArrayList(Arrays.asList(refs));
+
+ if (liteFeaturesAreOK && (site instanceof ExtendedSite) ) {
+
+ ExtendedSite extendedSite = (ExtendedSite)site;
+ LiteFeature[] liteFeaturesArray = extendedSite.getLiteFeatures();
+ if ( (liteFeaturesArray != null) && ( liteFeaturesArray.length != 0)) {
+ for(int i = 0; i < liteFeaturesArray.length; i++) {
+ liteFeatures.put(liteFeaturesArray[i].getVersionedIdentifier(), liteFeaturesArray[i]);
+ }
+ (new FeatureDownloader(siteFeatureReferences, collector, filter, ignores, monitor, true, liteFeatures)).run();
+ return;
+ } else {
+ liteFeaturesAreOK = false;
+ }
+ }
+
+
+
+ monitor.beginTask("", refs.length); //$NON-NLS-1$
+ ThreadGroup featureDownloaders = new ThreadGroup("FeatureDownloader"); //$NON-NLS-1$
+ int numberOfThreads = (refs.length > 5)? 5: refs.length;
+
+ Thread[] featureDownloader = new Thread[numberOfThreads];
+ for( int i = 0; i < numberOfThreads; i++) {
+ featureDownloader[i] = new Thread(featureDownloaders, new FeatureDownloader(siteFeatureReferences, collector, filter, ignores, monitor));
+ featureDownloader[i].start();
+ }
+
+ int i =0;
+ while(i < numberOfThreads){
+ if (monitor.isCanceled()) {
+ synchronized(siteFeatureReferences) {
+ siteFeatureReferences.clear();
+ }
+ }
+ try {
+ featureDownloader[i].join(250);
+ if(!featureDownloader[i].isAlive()){
+ i++;
+ }
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.internal.ui.search.ISearchQuery#getSearchSite()
+ */
+ public IQueryUpdateSiteAdapter getQuerySearchSite() {
+ return null;
+ }
+ }
+
+ public SiteSearchCategory() {
+ super(CATEGORY_ID);
+ queries = new IUpdateSearchQuery[] { new Query()};
+ }
+
+ public SiteSearchCategory(boolean liteFeaturesAreOK) {
+ this();
+ this.liteFeaturesAreOK = liteFeaturesAreOK;
+ queries = new IUpdateSearchQuery[] { new Query(liteFeaturesAreOK)};
+ }
+
+ public IUpdateSearchQuery[] getQueries() {
+ return queries;
+ }
+
+
+ private static class FeatureDownloader implements Runnable {
+
+ private List siteFeatureReferences;
+
+ private IProgressMonitor monitor;
+
+ private IUpdateSearchFilter filter;
+
+ private IUpdateSearchResultCollector collector;
+
+ private HashSet ignores;
+
+ private boolean liteFeaturesAreOK;
+
+ private Map liteFeatures;
+
+ public FeatureDownloader(List siteFeatureReferences, IUpdateSearchResultCollector collector, IUpdateSearchFilter filter, HashSet ignores, IProgressMonitor monitor) {
+ super();
+
+ this.collector = collector;
+ this.filter = filter;
+ this.ignores = ignores;
+ this.monitor = monitor;
+ this.siteFeatureReferences = siteFeatureReferences;
+ }
+
+ public FeatureDownloader(List siteFeatureReferences, IUpdateSearchResultCollector collector, IUpdateSearchFilter filter, HashSet ignores, IProgressMonitor monitor, boolean liteFeaturesAreOK, Map liteFeatures) {
+ this(siteFeatureReferences, collector, filter, ignores, monitor);
+ this.liteFeaturesAreOK = liteFeaturesAreOK && (liteFeatures != null);
+ this.liteFeatures = liteFeatures;
+ }
+
+ public void run() {
+
+ ISiteFeatureReference siteFeatureReference = null;
+
+ while (siteFeatureReferences.size() != 0) {
+
+ synchronized(siteFeatureReferences) {
+ try{
+ siteFeatureReference = (ISiteFeatureReference)siteFeatureReferences.remove(0);
+ }catch(IndexOutOfBoundsException e){
+ siteFeatureReference = null;
+ break;
+ }
+ }
+ if (siteFeatureReference != null) {
+ boolean skipFeature = false;
+ if (monitor.isCanceled())
+ break;
+ if (ignores.size() > 0) {
+ ICategory[] categories = siteFeatureReference.getCategories();
+
+ for (int j = 0; j < categories.length; j++) {
+ ICategory category = categories[j];
+ if (ignores.contains(category.getName())) {
+ skipFeature = true;
+ break;
+ }
+ }
+ }
+ try {
+ if (!skipFeature) {
+ if (filter.accept(siteFeatureReference)) {
+ IFeature feature = null;
+ if(liteFeaturesAreOK) {
+ feature = (IFeature)liteFeatures.get(siteFeatureReference.getVersionedIdentifier());
+ }
+ if (feature == null){
+ feature = siteFeatureReference.getFeature(null);
+ }
+ synchronized(siteFeatureReferences) {
+ if ( (feature != null) && (filter.accept(siteFeatureReference)) ) {
+ collector.accept(feature);
+ monitor.subTask(feature.getLabel());
+ }
+ }
+ }
+ }
+ } catch (CoreException e) {
+ UpdateCore.log(e);
+ } finally {
+ monitor.worked(1);
+ }
+ }
+ }
+
+ }
+ }
+
+ public boolean isLiteFeaturesAreOK() {
+ return liteFeaturesAreOK;
+ }
+
+ public void setLiteFeaturesAreOK(boolean liteFeaturesAreOK) {
+ this.liteFeaturesAreOK = liteFeaturesAreOK;
+ for( int i = 0; i < queries.length; i++) {
+ ((Query)queries[i]).setLiteFeaturesAreOK(liteFeaturesAreOK);
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/UpdatePolicy.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/UpdatePolicy.java
new file mode 100644
index 0000000..6e62a86
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/UpdatePolicy.java
@@ -0,0 +1,316 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 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
+ * James D Miles (IBM Corp.) - bug 191368, Policy URL doesn't support UTF-8 characters
+ *******************************************************************************/
+package org.eclipse.update.internal.search;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.URLEncoder;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+import org.eclipse.update.internal.core.connection.ConnectionFactory;
+import org.eclipse.update.internal.core.connection.IResponse;
+import org.eclipse.update.search.IUpdateSiteAdapter;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ *
+ * This class opens connection to the update map resource
+ * and parses the file to load update URL mappings.
+ * These mappings are used to redirect new updates search
+ * when the redirection pattern matches.
+ */
+
+public class UpdatePolicy {
+ private static final String TAG_POLICY = "update-policy"; //$NON-NLS-1$
+ private static final String TAG_URL_MAP = "url-map"; //$NON-NLS-1$
+ private static final String ATT_URL = "url"; //$NON-NLS-1$
+ private static final String ATT_PATTERN = "pattern"; //$NON-NLS-1$
+ private static final String ATT_TYPE = "url-type"; //$NON-NLS-1$
+ private static final String ATT_TYPE_VALUE_UPDATE = "update"; //$NON-NLS-1$
+ //private static final String ATT_TYPE_VALUE_BOTH = "both"; //$NON-NLS-1$
+ private static final String ATT_TYPE_VALUE_DISCOVERY = "discovery"; //$NON-NLS-1$
+
+ private static final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+
+ private static class MapSite implements IUpdateSiteAdapter {
+ private URL url;
+ public MapSite(URL url) {
+ this.url = url;
+ }
+ public String getLabel() {
+ if (url == null) {
+ return ""; //$NON-NLS-1$
+ }
+ return url.toString();
+ }
+ public URL getURL() {
+ return url;
+ }
+ }
+
+ private static class UpdateMapEntry {
+ private IUpdateSiteAdapter site;
+ private String pattern;
+
+ public UpdateMapEntry(String pattern, URL url) {
+ this.pattern = pattern;
+ this.site = new MapSite(url);
+ }
+ public IUpdateSiteAdapter getSite() {
+ return site;
+ }
+ public boolean matches(String id) {
+ return id.startsWith(pattern);
+ }
+ public String getPattern() {
+ return pattern;
+ }
+ }
+
+ private ArrayList entries;
+ private ArrayList discoveryEntries;
+ private IUpdateSiteAdapter defaultSite;
+ private IUpdateSiteAdapter defaultDiscoverySite;
+ private boolean loaded = false;
+ private boolean fallbackAllowed = true;
+
+ public UpdatePolicy() {
+ entries = new ArrayList();
+ discoveryEntries = new ArrayList();
+ }
+
+ public void load(URL mapFile, IProgressMonitor monitor)
+ throws CoreException {
+ InputStream policyStream = null;
+ try {
+ IResponse response = ConnectionFactory.get(mapFile);
+ UpdateManagerUtils.checkConnectionResult(response, mapFile);
+ policyStream = response.getInputStream(monitor);
+ // the stream can be null if the user cancels the connection
+ if (policyStream == null)
+ return;
+
+ documentBuilderFactory.setNamespaceAware(true);
+ DocumentBuilder parser = documentBuilderFactory.newDocumentBuilder();
+ Document doc = parser.parse(new InputSource(policyStream));
+
+ processUpdatePolicy(doc);
+ loaded = true;
+ } catch (IOException e) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.SiteURLFactory_UnableToAccessSiteStream, (new String[] { mapFile == null ? "" : mapFile.toExternalForm() })), //$NON-NLS-1$
+ ISite.SITE_ACCESS_EXCEPTION,
+ e);
+ } catch (SAXException e) {
+ throw Utilities.newCoreException(
+ Messages.UpdatePolicy_parsePolicy,
+ 0,
+ e);
+
+ } catch(ParserConfigurationException e) {
+ throw Utilities.newCoreException(
+ Messages.UpdatePolicy_parsePolicy,
+ 0,
+ e);
+ } finally {
+ if (policyStream != null) {
+ try {
+ policyStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ public boolean isLoaded() {
+ return loaded;
+ }
+
+ /*
+ * Given the feature ID, returns the mapped update URL if
+ * found in the mappings. This URL will be used INSTEAD of
+ * the update URL encoded in the feature itself during the
+ * new update search.
+ * <p>In case of multiple matches (e.g. org.eclipse and org.eclipse.platform)
+ * the URL for the longer pattern will be picked (i.e. org.eclipse.platform).
+ */
+ public IUpdateSiteAdapter getMappedSite(String id) {
+ UpdateMapEntry lastEntry = null;
+ for (int i = 0; i < entries.size(); i++) {
+ UpdateMapEntry entry = (UpdateMapEntry) entries.get(i);
+ if (entry.matches(id)) {
+ if (lastEntry == null)
+ lastEntry = entry;
+ else {
+ // Choose the match with longer pattern.
+ // For example, if two matches are found:
+ // 'org.eclipse' and 'org.eclipse.platform',
+ // pick 'org.eclipse.platform'.
+ String pattern = entry.getPattern();
+ String lastPattern = lastEntry.getPattern();
+ if (pattern.length() > lastPattern.length())
+ lastEntry = entry;
+ }
+ }
+ }
+ if (lastEntry != null)
+ return lastEntry.getSite();
+ else
+ return defaultSite;
+ }
+
+ /*
+ * Given the feature ID, returns the mapped discovery URL if
+ * found in the mappings. This URL will be used INSTEAD of
+ * the discovery URL encoded in the feature itself during the
+ * new search.
+ * <p>In case of multiple matches (e.g. org.eclipse and org.eclipse.platform)
+ * the URL for the longer pattern will be picked (i.e. org.eclipse.platform).
+ */
+ public IUpdateSiteAdapter getMappedDiscoverySite(String id) {
+ UpdateMapEntry lastEntry = null;
+ for (int i = 0; i < discoveryEntries.size(); i++) {
+ UpdateMapEntry entry = (UpdateMapEntry) discoveryEntries.get(i);
+ if (entry.matches(id)) {
+ if (lastEntry == null)
+ lastEntry = entry;
+ else {
+ // Choose the match with longer pattern.
+ // For example, if two matches are found:
+ // 'org.eclipse' and 'org.eclipse.platform',
+ // pick 'org.eclipse.platform'.
+ String pattern = entry.getPattern();
+ String lastPattern = lastEntry.getPattern();
+ if (pattern.length() > lastPattern.length())
+ lastEntry = entry;
+ }
+ }
+ }
+ if (lastEntry != null)
+ return lastEntry.getSite();
+ else
+ return defaultDiscoverySite;
+ }
+
+ public boolean isFallbackAllowed() {
+ return fallbackAllowed;
+ }
+
+ private void reset() {
+ if (!entries.isEmpty())
+ entries.clear();
+ if (!discoveryEntries.isEmpty())
+ discoveryEntries.clear();
+ }
+
+ private void processUpdatePolicy(Document document) throws CoreException {
+ Node root = document.getDocumentElement();
+ reset();
+
+ if (root.getNodeName().equals(TAG_POLICY)==false)
+ throwCoreException("'"+TAG_POLICY+Messages.UpdatePolicy_policyExpected, null); //$NON-NLS-1$
+
+ NodeList nodes = root.getChildNodes();
+
+ for (int i=0; i<nodes.getLength(); i++) {
+ Node child = nodes.item(i);
+ if (child.getNodeType() != Node.ELEMENT_NODE)
+ continue;
+ String tag = child.getNodeName();
+ if (tag.equals(TAG_URL_MAP))
+ processMapNode(child);
+ }
+ }
+ private void processMapNode(Node node) throws CoreException {
+ String pattern = getAttribute(node, ATT_PATTERN);
+ String urlName = getAttribute(node, ATT_URL);
+ String type = getAttribute(node, ATT_TYPE);
+
+ assertNotNull(ATT_PATTERN, pattern);
+ assertNotNull(ATT_URL, urlName);
+
+ // empty url means feature is not updateable
+ if (urlName.trim().length() == 0) {
+ addUpdateEntry(pattern, null, type);
+ return;
+ }
+
+ try {
+ URL url = new URL(urlName);
+ URL resolvedURL = URLEncoder.encode(url);
+ addUpdateEntry(pattern, resolvedURL, type);
+ } catch (MalformedURLException e) {
+ throwCoreException(Messages.UpdatePolicy_invalidURL+urlName, null);
+ }
+ }
+
+ private void assertNotNull(String name, String value) throws CoreException {
+ if (value==null)
+ throwCoreException(name+Messages.UpdatePolicy_nameNoNull, null);
+ }
+
+ private String getAttribute(Node node, String name) {
+ NamedNodeMap attMap = node.getAttributes();
+ Node att = attMap.getNamedItem(name);
+ if (att==null) return null;
+ return att.getNodeValue();
+ }
+
+ private void addUpdateEntry(String pattern, URL url, String type) {
+ if (pattern.equalsIgnoreCase("*")) {//$NON-NLS-1$
+ if (type == null)
+ defaultSite = new MapSite(url);
+ else if (type.equals(ATT_TYPE_VALUE_UPDATE))
+ defaultSite = new MapSite(url);
+ else if (type.equals(ATT_TYPE_VALUE_DISCOVERY))
+ defaultDiscoverySite = new MapSite(url);
+ else {
+ defaultSite = new MapSite(url);
+ defaultDiscoverySite = new MapSite(url);
+ }
+ } else {
+ if (type == null )
+ entries.add(new UpdateMapEntry(pattern, url));
+ else if (type.equals(ATT_TYPE_VALUE_UPDATE))
+ entries.add(new UpdateMapEntry(pattern, url));
+ else if (type.equals(ATT_TYPE_VALUE_DISCOVERY))
+ discoveryEntries.add(new UpdateMapEntry(pattern, url));
+ else {
+ entries.add(new UpdateMapEntry(pattern, url));
+ discoveryEntries.add(new UpdateMapEntry(pattern, url));
+ }
+ }
+ }
+
+ private void throwCoreException(String message, Throwable e) throws CoreException {
+ String fullMessage = Messages.UpdatePolicy_UpdatePolicy+message;
+ throw Utilities.newCoreException(fullMessage, 0, e);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/UpdateSiteAdapter.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/UpdateSiteAdapter.java
new file mode 100644
index 0000000..85c1e59
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/UpdateSiteAdapter.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.search;
+
+import java.net.*;
+
+import org.eclipse.update.search.*;
+
+/**
+ */
+public class UpdateSiteAdapter implements IUpdateSiteAdapter {
+ private String label;
+ private URL url;
+
+ public UpdateSiteAdapter(String label, URL url) {
+ this.label = label;
+ this.url = url;
+ }
+ public URL getURL() {
+ return url;
+ }
+ public String getLabel() {
+ return label;
+ }
+/*
+ public ISite getSite(IProgressMonitor monitor) {
+ try {
+ return SiteManager.getSite(getURL(), monitor);
+ } catch (CoreException e) {
+ return null;
+ }
+ }
+*/
+ public String toString(){
+ return "" + getURL(); //$NON-NLS-1$
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/UpdatesSearchCategory.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/UpdatesSearchCategory.java
new file mode 100644
index 0000000..c21db09
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/search/UpdatesSearchCategory.java
@@ -0,0 +1,571 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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.update.internal.search;
+
+import java.util.ArrayList;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.PluginVersionIdentifier;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.configuration.IInstallConfiguration;
+import org.eclipse.update.configuration.ILocalSite;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IFeatureReference;
+import org.eclipse.update.core.IIncludedFeatureReference;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.ISiteFeatureReference;
+import org.eclipse.update.core.IURLEntry;
+import org.eclipse.update.core.IUpdateConstants;
+import org.eclipse.update.core.SiteManager;
+import org.eclipse.update.core.VersionedIdentifier;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.operations.FeatureHierarchyElement;
+import org.eclipse.update.internal.operations.UpdateUtils;
+import org.eclipse.update.operations.IInstallFeatureOperation;
+import org.eclipse.update.operations.OperationsManager;
+import org.eclipse.update.search.IQueryUpdateSiteAdapter;
+import org.eclipse.update.search.IUpdateSearchFilter;
+import org.eclipse.update.search.IUpdateSearchQuery;
+import org.eclipse.update.search.IUpdateSearchResultCollector;
+
+public class UpdatesSearchCategory extends BaseSearchCategory {
+ private static final String CATEGORY_ID =
+ "org.eclipse.update.core.new-updates"; //$NON-NLS-1$
+ private IFeature [] features;
+ private boolean automatic;
+
+ class Candidate {
+ ArrayList children;
+ Candidate parent;
+ IFeatureReference ref;
+ public Candidate(IFeatureReference ref) {
+ this.ref = ref;
+ }
+ public Candidate(IFeatureReference ref, Candidate parent) {
+ this(ref);
+ this.parent = parent;
+ }
+ public void add(Candidate child) {
+ if (children == null)
+ children = new ArrayList();
+ child.setParent(this);
+ children.add(child);
+ }
+ void setParent(Candidate parent) {
+ this.parent = parent;
+ }
+ public IFeatureReference getReference() {
+ return ref;
+ }
+ void setReference(IFeatureReference ref) {
+ this.ref = ref;
+ }
+ public IFeature getFeature(IProgressMonitor monitor) {
+ try {
+ return ref.getFeature(monitor);
+ } catch (CoreException e) {
+ return null;
+ }
+ }
+ public Candidate getParent() {
+ return parent;
+ }
+ public Candidate getRoot() {
+ Candidate root = this;
+
+ while (root.getParent() != null) {
+ root = root.getParent();
+ }
+ return root;
+ }
+ public IURLEntry getUpdateEntry() {
+ int location = IUpdateConstants.SEARCH_ROOT;
+
+ if (ref instanceof IIncludedFeatureReference)
+ location =
+ ((IIncludedFeatureReference) ref).getSearchLocation();
+ if (parent == null || location == IUpdateConstants.SEARCH_SELF) {
+ return getFeature(null).getUpdateSiteEntry();
+ }
+ return getRoot().getUpdateEntry();
+ }
+ public String toString() {
+ return ref.toString();
+ }
+ public boolean equals(Object source) {
+ if (source instanceof Candidate) {
+ return this.ref.equals(((Candidate) source).getReference());
+ }
+ if (source instanceof IFeatureReference) {
+ return this.ref.equals(source);
+ }
+ return false;
+ }
+ public void addToFlatList(ArrayList list, boolean updatableOnly) {
+ // add itself
+ if (!updatableOnly || isUpdatable())
+ list.add(this);
+ // add children
+ if (children != null) {
+ for (int i = 0; i < children.size(); i++) {
+ Candidate child = (Candidate) children.get(i);
+ child.addToFlatList(list, updatableOnly);
+ }
+ }
+ }
+ public boolean isUpdatable() {
+ return (parent == null);
+ }
+ }
+
+ private static class Hit {
+ IFeatureReference ref;
+ IInstallFeatureOperation patchFor;
+ boolean patch;
+ IInstallFeatureOperation job;
+
+ public Hit(IFeature candidate, IFeatureReference ref) {
+ this.ref = ref;
+ }
+ public Hit(IFeature candidate, IFeatureReference ref, boolean patch) {
+ this(candidate, ref);
+ this.patch = patch;
+ }
+
+ public Hit(IFeature candidate, IFeatureReference ref, IInstallFeatureOperation patchFor) {
+ this(candidate, ref, true);
+ this.patchFor = patchFor;
+ }
+
+ public IInstallFeatureOperation getJob() {
+ if (job == null) {
+ try {
+ IFeature feature = ref.getFeature(null);
+ job = OperationsManager.getOperationFactory().createInstallOperation(null, feature, null, null, null);
+ } catch (CoreException e) {
+ UpdateCore.log(e);
+ }
+ }
+ return job;
+ }
+
+ public boolean isPatch() {
+ return patch;
+ }
+ public IInstallFeatureOperation getPatchedJob() {
+ return patchFor;
+ }
+ }
+
+ public class UpdateQuery implements IUpdateSearchQuery {
+ IFeature candidate;
+ IQueryUpdateSiteAdapter adapter;
+
+ public UpdateQuery(
+ IFeature candidate,
+ IURLEntry updateEntry) {
+ this.candidate = candidate;
+ if (updateEntry != null && updateEntry.getURL() != null)
+ adapter =
+ new QueryUpdateSiteAdapter(
+ getLabelForEntry(updateEntry),
+ updateEntry.getURL(),
+ candidate.getVersionedIdentifier().getIdentifier());
+ }
+ private String getLabelForEntry(IURLEntry entry) {
+ String label = entry.getAnnotation();
+ if (label == null || label.length() == 0)
+ label = entry.getURL().toString();
+ return label;
+ }
+
+ public IQueryUpdateSiteAdapter getQuerySearchSite() {
+ return adapter;
+ }
+ private boolean isBroken() {
+ try {
+ IStatus status =
+ SiteManager.getLocalSite().getFeatureStatus(candidate);
+ return status.getSeverity() == IStatus.ERROR;
+ } catch (CoreException e) {
+ return false;
+ }
+ }
+ private boolean isMissingOptionalChildren(IFeature feature) {
+ try {
+ IIncludedFeatureReference[] children =
+ feature.getIncludedFeatureReferences();
+ for (int i = 0; i < children.length; i++) {
+ IIncludedFeatureReference ref = children[i];
+ try {
+ IFeature child = ref.getFeature(null);
+ // If we are here, the child is not missing.
+ // Check it's children recursively.
+ if (isMissingOptionalChildren(child))
+ return true;
+ } catch (CoreException e) {
+ // Missing child. Return true if optional,
+ // otherwise it is a broken feature that we
+ // do not care about.
+ if (ref.isOptional()) {
+ return FeatureHierarchyElement.hasOlderVersion(ref);
+ }
+ }
+ }
+ } catch (CoreException e) {
+ }
+ return false;
+ }
+ public void run(
+ ISite site,
+ String[] categoriesToSkip,
+ IUpdateSearchFilter filter,
+ IUpdateSearchResultCollector collector,
+ IProgressMonitor monitor) {
+ ArrayList hits = new ArrayList();
+ boolean broken = isBroken();
+ boolean missingOptionalChildren = false;
+
+ // Don't bother to compute missing optional children
+ // if the feature is broken - all we want is to
+ // see if we should allow same-version re-install.
+ if (!broken)
+ missingOptionalChildren = isMissingOptionalChildren(candidate);
+ ISiteFeatureReference[] refs = site.getFeatureReferences();
+ monitor.beginTask("", refs.length + 1); //$NON-NLS-1$
+ ArrayList updateJobs = new ArrayList();
+ for (int i = 0; i < refs.length; i++) {
+ ISiteFeatureReference ref = refs[i];
+ try {
+ if (isNewerVersion(candidate.getVersionedIdentifier(),ref.getVersionedIdentifier())) {
+ Hit h = new Hit(candidate, ref);
+ hits.add(h);
+ IInstallFeatureOperation job = h.getJob();
+ if (job != null)
+ updateJobs.add(job);
+ } else {
+ // accept the same feature if the installed
+ // feature is broken
+ if ((broken || missingOptionalChildren)
+ && candidate.getVersionedIdentifier().equals(
+ ref.getVersionedIdentifier())){
+ hits.add(new Hit(candidate, ref));
+ continue;
+ }
+ else {
+ // check for patches
+ if (isPatch(candidate, ref)){
+ hits.add(new Hit(candidate, ref, true));
+ continue;
+ }
+ }
+ }
+ } catch (CoreException e) {
+ }
+ monitor.worked(1);
+ if (monitor.isCanceled()){
+ return;
+ }
+
+ }
+ // accept patches for updated features
+ for (int n = 0; n < updateJobs.size(); n++) {
+ IInstallFeatureOperation job = (IInstallFeatureOperation) updateJobs
+ .get(n);
+ IFeature newCandidate = job.getFeature();
+ for (int i = 0; i < refs.length; i++) {
+ ISiteFeatureReference ref = refs[i];
+ if (isPatch(newCandidate, ref)) {
+ Hit h = new Hit(newCandidate, ref, job);
+ hits.add(h);
+ continue;
+ }
+ //monitor.worked(1);
+ if (monitor.isCanceled()) {
+ return;
+ }
+ }
+ }
+ if (hits.size() > 0) {
+ collectValidHits(hits, filter, collector);
+ }
+ monitor.worked(1);
+ monitor.done();
+ }
+
+ /**
+ * Returns IFeature associated with the IUpdateSearchQuery
+ */
+ public IFeature getFeature() {
+ return candidate;
+ }
+ }
+
+ private ArrayList candidates;
+
+ public UpdatesSearchCategory() {
+ this(true);
+ }
+
+ public UpdatesSearchCategory(boolean automatic) {
+ super(CATEGORY_ID);
+ this.automatic = automatic;
+ }
+
+ private void collectValidHits(
+ ArrayList hits,
+ IUpdateSearchFilter filter,
+ IUpdateSearchResultCollector collector) {
+ //Object[] array = hits.toArray();
+ IFeature topHit = null;
+ for (int i = 0; i < hits.size(); i++) {
+ Hit hit = (Hit) hits.get(i);
+ IInstallFeatureOperation job = hit.getJob();
+ if (job == null)
+ continue;
+ // do not accept updates without a license
+ if (!UpdateUtils.hasLicense(job.getFeature())) {
+ UpdateCore.log(job.getFeature().getVersionedIdentifier() + ": " + Messages.DefaultFeatureParser_NoLicenseText, null); //$NON-NLS-1$
+ continue;
+ }
+ IStatus status = null;
+
+ // Fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=132450
+ // Only validate for automatic updates because
+ // non-automatic once will arrive in the review wizard
+ // where additional validation will be performed
+ if (automatic) {
+ if( hit.getPatchedJob()==null){
+ status = OperationsManager.getValidator().validatePendingInstall(job.getOldFeature(), job.getFeature());
+ }else{
+ status = OperationsManager.getValidator().validatePendingChanges(new IInstallFeatureOperation[]{hit.getPatchedJob(), job});
+ }
+ }
+ if (status == null || status.getCode() == IStatus.WARNING) {
+ if (hit.isPatch()) {
+ IFeature patch = job.getFeature();
+ // Do not add the patch if already installed
+ IFeature[] sameId = UpdateUtils.getInstalledFeatures(patch, false);
+ if (sameId.length==0) {
+ if (filter.accept(patch))
+ collector.accept(patch);
+ }
+ }
+ else {
+ topHit = job.getFeature();
+ if (filter.accept(topHit))
+ collector.accept(topHit);
+ }
+ }
+ }
+ }
+
+ private void initialize() {
+ candidates = new ArrayList();
+ try {
+ ILocalSite localSite = SiteManager.getLocalSite();
+ IInstallConfiguration config = localSite.getCurrentConfiguration();
+ IConfiguredSite[] isites = config.getConfiguredSites();
+ for (int i = 0; i < isites.length; i++) {
+ contributeCandidates(isites[i]);
+ }
+ } catch (CoreException e) {
+ UpdateCore.log(
+ Messages.UpdatesSearchCategory_errorSearchingForUpdates,
+ e);
+ }
+ }
+
+ private void contributeCandidates(IConfiguredSite isite)
+ throws CoreException {
+ IFeatureReference[] refs = isite.getConfiguredFeatures();
+ ArrayList candidatesPerSite = new ArrayList();
+ for (int i = 0; i < refs.length; i++) {
+ IFeatureReference ref = refs[i];
+ // Don't waste time searching for updates to
+ // patches.
+ try {
+ if (UpdateUtils.isPatch(ref.getFeature(null)))
+ continue;
+ }
+ catch (CoreException e) {
+ continue;
+ }
+ Candidate c = new Candidate(ref);
+ candidatesPerSite.add(c);
+ }
+ // Create a tree from a flat list
+ buildHierarchy(candidatesPerSite);
+ // Add the remaining root candidates to
+ // the global list of candidates.
+ candidates.addAll(candidatesPerSite);
+ }
+
+ private void buildHierarchy(ArrayList candidates) throws CoreException {
+ Candidate[] array =
+ (Candidate[]) candidates.toArray(new Candidate[candidates.size()]);
+ // filter out included features so that only top-level features remain on the list
+ for (int i = 0; i < array.length; i++) {
+ Candidate parent = array[i];
+ IFeature feature = parent.getFeature(null);
+ IFeatureReference[] included =
+ feature.getIncludedFeatureReferences();
+ for (int j = 0; j < included.length; j++) {
+ IFeatureReference fref = included[j];
+ Candidate child = findCandidate(candidates, fref);
+ if (child != null) {
+ parent.add(child);
+ child.setReference(fref);
+ candidates.remove(child);
+ }
+ }
+ }
+ }
+ private Candidate findCandidate(ArrayList list, IFeatureReference ref) {
+ for (int i = 0; i < list.size(); i++) {
+ Candidate c = (Candidate) list.get(i);
+ if (c.ref.equals(ref))
+ return c;
+ }
+ return null;
+ }
+
+ public IUpdateSearchQuery[] getQueries() {
+ initialize();
+ ArrayList allCandidates = getAllCandidates();
+
+ IUpdateSearchQuery[] queries =
+ new IUpdateSearchQuery[allCandidates.size()];
+ for (int i = 0; i < queries.length; i++) {
+ Candidate candidate = (Candidate) allCandidates.get(i);
+ IFeature feature = candidate.getFeature(null);
+ IURLEntry updateEntry = candidate.getUpdateEntry();
+ if (feature == null) {
+ queries[i] = null;
+ } else {
+ queries[i] = new UpdateQuery(feature, updateEntry);
+ }
+ }
+ return queries;
+ }
+
+/**
+ * Sets the features for which new updates need to be found. If
+ * not set, updates will be searched for all the installed
+ * and configured features.
+ * @param features the features to search updates for
+ */
+ public void setFeatures(IFeature [] features) {
+ this.features = features;
+ }
+
+/**
+ * Returns an array of features for which updates need to
+ * be found.
+ * @return an array of features or <samp>null</samp> if not
+ * set.
+ */
+ public IFeature [] getFeatures() {
+ return features;
+ }
+ /**
+ * @param fvi
+ * @param cvi
+ * @return fvi < cvi
+ */
+ private boolean isNewerVersion(
+ VersionedIdentifier fvi,
+ VersionedIdentifier cvi) {
+ if (!fvi.getIdentifier().equals(cvi.getIdentifier()))
+ return false;
+ PluginVersionIdentifier fv = fvi.getVersion();
+ PluginVersionIdentifier cv = cvi.getVersion();
+ String mode = getUpdateVersionsMode();
+ boolean greater = cv.isGreaterThan(fv);
+ if (!greater)
+ return false;
+ if (mode.equals(UpdateCore.EQUIVALENT_VALUE))
+ return cv.isEquivalentTo(fv);
+ else if (mode.equals(UpdateCore.COMPATIBLE_VALUE))
+ return cv.isCompatibleWith(fv);
+ else
+ return false;
+ }
+
+ private boolean isPatch(IFeature candidate, ISiteFeatureReference ref) {
+ if (ref.isPatch() == false)
+ return false;
+ try {
+ IFeature feature = ref.getFeature(null);
+ if( UpdateUtils.isPatch(candidate, feature))
+ return true;
+ // Check if patch is for children
+ try {
+ IIncludedFeatureReference[] children =
+ candidate.getIncludedFeatureReferences();
+ for (int i = 0; i < children.length; i++) {
+ IIncludedFeatureReference cref = children[i];
+ try {
+ IFeature child = cref.getFeature(null);
+ if (isPatch(child, ref))
+ return true;
+ } catch (CoreException e) {
+ }
+ }
+ } catch (CoreException e) {
+ }
+ return false;
+ } catch (CoreException e) {
+ return false;
+ }
+ }
+
+ private String getUpdateVersionsMode() {
+ Preferences store = UpdateCore.getPlugin().getPluginPreferences();
+ return store.getString(UpdateCore.P_UPDATE_VERSIONS);
+ }
+/*
+ * This method recursively walks the list of candidates
+ * building the flat that starts with the roots but
+ * also includes all the children that are updatable
+ * (use 'include' clause with a match that is not 'perfect').
+ */
+ private ArrayList getAllCandidates() {
+ ArrayList selected = new ArrayList();
+ for (int i=0; i<candidates.size(); i++) {
+ Candidate c = (Candidate)candidates.get(i);
+ if (isOnTheList(c))
+ c.addToFlatList(selected, true);
+ }
+ return selected;
+ }
+
+ private boolean isOnTheList(Candidate c) {
+ if (features==null) return true;
+ VersionedIdentifier vid;
+ try {
+ vid = c.getReference().getVersionedIdentifier();
+ }
+ catch (CoreException e) {
+ return false;
+ }
+ for (int i=0; i<features.length; i++) {
+ IFeature feature = features[i];
+ VersionedIdentifier fvid = feature.getVersionedIdentifier();
+ if (fvid.equals(vid))
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/CertificatePair.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/CertificatePair.java
new file mode 100644
index 0000000..9b0c4c1
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/CertificatePair.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.security;
+
+ import java.security.cert.*;
+
+/**
+ *
+ */
+public class CertificatePair {
+ private Certificate root;
+ private Certificate issuer;
+
+
+
+ /**
+ * Gets the root.
+ * @return Returns a Certificate
+ */
+ public Certificate getRoot() {
+ return root;
+ }
+
+ /**
+ * Sets the root.
+ * @param root The root to set
+ */
+ public void setRoot(Certificate root) {
+ this.root = root;
+ }
+
+ /**
+ * Gets the issuer.
+ * @return Returns a Certificate
+ */
+ public Certificate getIssuer() {
+ return issuer;
+ }
+
+ /**
+ * Sets the issuer.
+ * @param issuer The issuer to set
+ */
+ public void setIssuer(Certificate issuer) {
+ this.issuer = issuer;
+ }
+
+ /*
+ * @see Object#equals(Object)
+ */
+ public boolean equals(Object obj) {
+
+ if (obj==null) return false;
+
+ if (!(obj instanceof CertificatePair)) return false;
+
+ if (root==null || issuer==null) return false;
+
+ CertificatePair pair = (CertificatePair)obj;
+
+ return (root.equals(pair.getRoot()) && issuer.equals(pair.getIssuer()));
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/JarVerificationResult.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/JarVerificationResult.java
new file mode 100644
index 0000000..87406f7
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/JarVerificationResult.java
@@ -0,0 +1,334 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.update.internal.security;
+
+import java.security.*;
+import java.security.cert.*;
+import java.security.cert.Certificate;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.Messages;
+
+/**
+ * Result of the service
+ */
+public class JarVerificationResult implements IVerificationResult {
+
+
+ private int resultCode;
+ private int verificationCode;
+ private Exception resultException;
+ private List /*of Certificates[] */
+ certificates;
+ private CertificatePair[] rootCertificates;
+ private CertificatePair foundCertificate; // certificate found in one keystore
+
+ private String signerInfo;
+ private String verifierInfo;
+ private ContentReference contentReference;
+ private IFeature feature;
+ private boolean featureVerification;
+ private boolean alreadySeen;
+
+ public JarVerificationResult() {
+ }
+
+ /*
+ *
+ */
+ public int getResultCode() {
+ return resultCode;
+ }
+
+ /*
+ *
+ */
+ public Exception getVerificationException() {
+ return resultException;
+ }
+
+ /*
+ *
+ */
+ public void setResultCode(int newResultCode) {
+ resultCode = newResultCode;
+ }
+
+ /*
+ *
+ */
+ public void setResultException(Exception newResultException) {
+ resultException = newResultException;
+ }
+
+ /*
+ *
+ */
+ public int getVerificationCode() {
+ return verificationCode;
+ }
+
+ /*
+ *
+ */
+ public void setVerificationCode(int verificationCode) {
+ this.verificationCode = verificationCode;
+ }
+
+ /*
+ * adds an array of Certificates to the list
+ * force recomputation of root cert
+ */
+ public void addCertificates(Certificate[] certs) {
+ if (certificates == null)
+ certificates = new ArrayList();
+ certificates.add(certs);
+ rootCertificates = null;
+ }
+
+ /*
+ * Returns the list of root certificates
+ * The list of certificates we received is an array of certificates
+ * we have to determine
+ * 1) how many chain do we have (a chain stops when verifier of a cert is
+ * not the signer of the next cert in the list
+ * 2) build a cert with the leaf signer and the root verifier for each chain
+ */
+ public CertificatePair[] getRootCertificates() {
+ if (rootCertificates == null) {
+ rootCertificates = new CertificatePair[0];
+ List rootCertificatesList = new ArrayList();
+ if (certificates != null && certificates.size() > 0) {
+ Iterator iter = certificates.iterator();
+ while (iter.hasNext()) {
+
+ Certificate[] certs = (Certificate[]) iter.next();
+ if (certs != null && certs.length > 0) {
+
+ CertificatePair pair = new CertificatePair();
+ pair.setIssuer(certs[0]);
+
+ for (int i = 0; i < certs.length - 1; i++) {
+ X509Certificate x509certRoot = (X509Certificate) certs[i];
+ X509Certificate x509certIssuer = (X509Certificate) certs[i+1];
+ if (!x509certRoot.getIssuerDN().equals(x509certIssuer.getSubjectDN())) {
+ pair.setRoot(x509certRoot);
+ if (!rootCertificatesList.contains(pair)) {
+ rootCertificatesList.add(pair);
+ }
+ pair = new CertificatePair();
+ pair.setIssuer(x509certIssuer);
+ }
+ }
+
+ // add the latest one
+ if (pair != null) {
+ pair.setRoot(certs[certs.length - 1]);
+ if (!rootCertificatesList.contains(pair)) {
+ rootCertificatesList.add(pair);
+ }
+ }
+ }
+ }
+
+ }
+
+ if (rootCertificatesList.size() > 0) {
+ rootCertificates = new CertificatePair[rootCertificatesList.size()];
+ rootCertificatesList.toArray(rootCertificates);
+ }
+ }
+ return rootCertificates;
+ }
+
+ /*
+ *
+ */
+ private CertificatePair getFoundCertificate() {
+ return foundCertificate;
+ }
+
+ /*
+ *
+ */
+ public void setFoundCertificate(CertificatePair foundCertificate) {
+ this.foundCertificate = foundCertificate;
+ }
+
+
+ /*
+ * Initializes the signerInfo and the VerifierInfo from the Certificate Pair
+ */
+ private void initializeCertificates(){
+ X509Certificate certRoot = null;
+ X509Certificate certIssuer = null;
+ CertificatePair trustedCertificate;
+ if (getFoundCertificate() == null) {
+ CertificatePair[] certs = getRootCertificates();
+ if (certs.length == 0)
+ return;
+ trustedCertificate = certs[0];
+ } else {
+ trustedCertificate = getFoundCertificate();
+ }
+ certRoot = (X509Certificate) trustedCertificate.getRoot();
+ certIssuer = (X509Certificate) trustedCertificate.getIssuer();
+
+ StringBuffer strb = new StringBuffer();
+ strb.append(issuerString(certIssuer.getSubjectDN()));
+ strb.append("\r\n"); //$NON-NLS-1$
+ strb.append(NLS.bind(Messages.JarVerificationResult_ValidBetween, (new String[] { dateString(certIssuer.getNotBefore()), dateString(certIssuer.getNotAfter()) })));
+ strb.append(checkValidity(certIssuer));
+ signerInfo = strb.toString();
+ if (certIssuer != null && !certIssuer.equals(certRoot)) {
+ strb = new StringBuffer();
+ strb.append(issuerString(certIssuer.getIssuerDN()));
+ strb.append("\r\n"); //$NON-NLS-1$
+ strb.append(NLS.bind(Messages.JarVerificationResult_ValidBetween, (new String[] { dateString(certRoot.getNotBefore()), dateString(certRoot.getNotAfter()) })));
+ strb.append(checkValidity(certRoot));
+ verifierInfo = strb.toString();
+ }
+
+ }
+
+ /*
+ * Returns a String to show if the certificate is valid
+ */
+ private String checkValidity(X509Certificate cert) {
+
+ try {
+ cert.checkValidity();
+ } catch (CertificateExpiredException e) {
+ return ("\r\n" + Messages.JarVerificationResult_ExpiredCertificate); //$NON-NLS-1$
+ } catch (CertificateNotYetValidException e) {
+ return ("\r\n" + Messages.JarVerificationResult_CertificateNotYetValid); //$NON-NLS-1$
+ }
+ return ("\r\n" + Messages.JarVerificationResult_CertificateValid); //$NON-NLS-1$
+ }
+
+ /*
+ * Returns the label String from a X50name
+ */
+ private String issuerString(Principal principal) {
+// 19902
+// try {
+// if (principal instanceof X500Name) {
+// StringBuffer buf = new StringBuffer();
+// X500Name name = (X500Name) principal;
+// buf.append((name.getDNQualifier() != null) ? name.getDNQualifier() + ", " : "");
+// buf.append(name.getCommonName());
+// buf.append((name.getOrganizationalUnit() != null) ? ", " + name.getOrganizationalUnit() : "");
+// buf.append((name.getOrganization() != null) ? ", " + name.getOrganization() : "");
+// buf.append((name.getLocality() != null) ? ", " + name.getLocality() : "");
+// buf.append((name.getCountry() != null) ? ", " + name.getCountry() : "");
+// return new String(buf);
+// }
+// } catch (Exception e) {
+// UpdateCore.warn("Error parsing X500 Certificate",e);
+// }
+ return principal.toString();
+ }
+
+ /*
+ *
+ */
+ private String dateString(Date date) {
+ return DateFormat.getDateInstance().format(date);
+ }
+
+ /*
+ *
+ */
+ public String getSignerInfo() {
+ if (signerInfo==null) initializeCertificates();
+ return signerInfo;
+ }
+
+ /*
+ *
+ */
+ public String getVerifierInfo() {
+ if (signerInfo==null) initializeCertificates();
+ return verifierInfo;
+ }
+
+ /*
+ *
+ */
+ public ContentReference getContentReference() {
+ return contentReference;
+ }
+
+ /*
+ *
+ */
+ public void setContentReference(ContentReference ref) {
+ this.contentReference = ref;
+ }
+
+
+ /*
+ *
+ */
+ public IFeature getFeature() {
+ return feature;
+ }
+
+ /*
+ *
+ */
+ public void setFeature(IFeature feature) {
+ this.feature = feature;
+ }
+
+ /*
+ *
+ */
+ public String getText() {
+ return null;
+ }
+
+
+ /*
+ *
+ */
+ public boolean isFeatureVerification() {
+ return featureVerification;
+ }
+
+ /*
+ *
+ */
+ public void isFeatureVerification(boolean featureVerification) {
+ this.featureVerification = featureVerification;
+ }
+
+ /*
+ *
+ */
+ public boolean alreadySeen() {
+ return alreadySeen;
+ }
+
+ /*
+ *
+ */
+ public boolean alreadySeen(boolean seen) {
+ return this.alreadySeen = seen;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/JarVerifier.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/JarVerifier.java
new file mode 100644
index 0000000..d0b25b2
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/JarVerifier.java
@@ -0,0 +1,457 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.security;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.ZipException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.ContentReference;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IVerificationResult;
+import org.eclipse.update.core.IVerifier;
+import org.eclipse.update.core.InstallMonitor;
+import org.eclipse.update.core.JarContentReference;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.core.Verifier;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.connection.ConnectionFactory;
+
+/**
+ * The JarVerifier will check the integrity of the JAR.
+ * If the Jar is signed and the integrity is validated,
+ * it will check if one of the certificate of each file
+ * is in one of the keystore.
+ *
+ */
+
+public class JarVerifier extends Verifier {
+
+ private static final String MANIFEST = "META-INF"; //$NON-NLS-1$
+
+ private JarVerificationResult result;
+ private List /*of CertificatePair*/
+ trustedCertificates;
+ private boolean acceptUnsignedFiles;
+ private List /* of KeyStore */
+ listOfKeystores;
+ private IProgressMonitor monitor;
+ private File jarFile;
+
+ private static byte[] buffer = new byte[8192];
+
+ /*
+ * Default Constructor
+ */
+ public JarVerifier() {
+ initialize();
+ }
+
+ /*
+ * Returns the list of the keystores.
+ */
+ private List getKeyStores() throws CoreException {
+ if (listOfKeystores == null) {
+ listOfKeystores = new ArrayList(0);
+ KeyStores listOfKeystoreHandles = new KeyStores();
+ InputStream in = null;
+ KeyStore keystore = null;
+ KeystoreHandle handle = null;
+ while (listOfKeystoreHandles.hasNext()) {
+ try {
+ handle = listOfKeystoreHandles.next();
+ in = ConnectionFactory.get(handle.getLocation()).getInputStream();
+ try {
+ keystore = KeyStore.getInstance(handle.getType());
+ keystore.load(in, null); // no password
+ } catch (NoSuchAlgorithmException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.JarVerifier_UnableToFindEncryption, (new String[] { handle.getLocation().toExternalForm() })), e);
+ } catch (CertificateException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.JarVerifier_UnableToLoadCertificate, (new String[] { handle.getLocation().toExternalForm() })), e);
+ } catch (KeyStoreException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.JarVerifier_UnableToFindProviderForKeystore, (new String[] { handle.getType() })), e);
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ } // nothing
+ }
+ } // try loading a keyStore
+
+ // keystore was loaded
+ listOfKeystores.add(keystore);
+ } catch (IOException e) {
+ // nothing... if the keystore doesn't exist, continue
+ }
+
+ } // while all key stores
+
+ }
+
+ return listOfKeystores;
+ }
+
+ /*
+ *
+ */
+ private void initialize() {
+ result = null;
+ trustedCertificates = null;
+ acceptUnsignedFiles = false;
+ listOfKeystores = null;
+ }
+
+ /*
+ * init
+ */
+ private void init(IFeature feature, ContentReference contentRef) throws CoreException {
+ jarFile = null;
+ if (contentRef instanceof JarContentReference) {
+ JarContentReference jarReference = (JarContentReference) contentRef;
+ try {
+ jarFile = jarReference.asFile();
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL)
+ UpdateCore.debug("Attempting to read JAR file:"+jarFile); //$NON-NLS-1$
+
+ // # of entries
+ if (!jarFile.exists()) throw new IOException();
+ JarFile jar = new JarFile(jarFile);
+ if (jar !=null){
+ try {
+ jar.close();
+ } catch (IOException ex) {
+ // unchecked
+ }
+ }
+ } catch (ZipException e){
+ throw Utilities.newCoreException(NLS.bind(Messages.JarVerifier_InvalidJar, (new String[] { jarReference.toString() })), e);
+ } catch (IOException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.JarVerifier_UnableToAccessJar, (new String[] { jarReference.toString() })), e);
+ }
+ }
+
+ result = new JarVerificationResult();
+ result.setVerificationCode(IVerificationResult.UNKNOWN_ERROR);
+ result.setResultException(null);
+ result.setFeature(feature);
+ result.setContentReference(contentRef);
+ }
+
+ /*
+ * Returns true if one of the certificate exists in the keystore
+ */
+ private boolean existsInKeystore(Certificate cert) throws CoreException {
+ try {
+ List keyStores = getKeyStores();
+ if (!keyStores.isEmpty()) {
+ Iterator listOfKeystores = keyStores.iterator();
+ while (listOfKeystores.hasNext()) {
+ KeyStore keystore = (KeyStore) listOfKeystores.next();
+
+ if (keystore.getCertificateAlias(cert) != null) {
+ return true;
+ }
+ }
+ }
+ } catch (KeyStoreException e) {
+ throw Utilities.newCoreException(Messages.JarVerifier_KeyStoreNotLoaded, e);
+ }
+ return false;
+ }
+
+ /*
+ *
+ */
+ private List readJarFile(JarFile jarFile, String identifier)
+ throws IOException, InterruptedException {
+ List list = new ArrayList();
+
+ Enumeration entries = jarFile.entries();
+ JarEntry currentEntry = null;
+ InputStream in = null;
+ if (monitor != null)
+ monitor.setTaskName(NLS.bind(Messages.JarVerifier_Verify, (new String[] { identifier == null ? jarFile.getName(): identifier })));
+
+ try {
+ while (entries.hasMoreElements()) {
+ currentEntry = (JarEntry) entries.nextElement();
+ list.add(currentEntry);
+ in = jarFile.getInputStream(currentEntry);
+ while ((in.read(buffer, 0, buffer.length)) != -1) {
+ // Security error thrown if tempered
+ }
+ if (in!=null)
+ in.close();
+ }
+ } catch (IOException e) {
+ result.setVerificationCode(IVerificationResult.UNKNOWN_ERROR);
+ result.setResultException(e);
+ } finally {
+ try {
+ if (in != null)
+ in.close();
+ } catch (IOException e1) {
+ // ignore
+ }
+ }
+
+ return list;
+ }
+
+ /*
+ * @param newMonitor org.eclipse.core.runtime.IProgressMonitor
+ */
+ public void setMonitor(IProgressMonitor newMonitor) {
+ monitor = newMonitor;
+ }
+
+ /*
+ * @see IVerifier#verify(IFeature,ContentReference,boolean, InstallMonitor)
+ */
+ public IVerificationResult verify(
+ IFeature feature,
+ ContentReference reference,
+ boolean isFeatureVerification,
+ InstallMonitor monitor)
+ throws CoreException {
+
+ if (reference == null)
+ return result;
+
+ // if parent knows how to verify, ask the parent first
+ if (getParent() != null) {
+ IVerificationResult vr =
+ getParent().verify(feature, reference, isFeatureVerification, monitor);
+ if (vr.getVerificationCode() != IVerificationResult.TYPE_ENTRY_UNRECOGNIZED)
+ return vr;
+ }
+
+ // the parent couldn't verify
+ setMonitor(monitor);
+ init(feature, reference);
+ result.isFeatureVerification(isFeatureVerification);
+
+ if (jarFile!=null) {
+ result = verify(jarFile.getAbsolutePath(), reference.getIdentifier());
+ } else {
+ result.setVerificationCode(IVerificationResult.TYPE_ENTRY_UNRECOGNIZED);
+ }
+
+ return result;
+ }
+
+ /*
+ *
+ */
+ private JarVerificationResult verify(String file, String identifier) {
+
+ try {
+
+ // verify integrity
+ verifyIntegrity(file, identifier);
+
+ // do not close input stream
+ // as verifyIntegrity already did it
+
+ //if user already said yes
+ result.alreadySeen(alreadyValidated());
+
+ // verify source certificate
+ if (result.getVerificationCode()
+ == IVerificationResult.TYPE_ENTRY_SIGNED_UNRECOGNIZED) {
+ verifyAuthentication();
+ }
+
+ // save the fact the file is not signed, so the user will not be prompted again
+ if (result.getVerificationCode()
+ == IVerificationResult.TYPE_ENTRY_NOT_SIGNED) {
+ acceptUnsignedFiles = true;
+ }
+
+ } catch (Exception e) {
+ result.setVerificationCode(IVerificationResult.UNKNOWN_ERROR);
+ result.setResultException(e);
+ }
+
+ if (monitor != null) {
+ monitor.worked(1);
+ if (monitor.isCanceled()) {
+ result.setVerificationCode(IVerificationResult.VERIFICATION_CANCELLED);
+ }
+ }
+
+ return result;
+ }
+
+ /*
+ * Verifies that each file has at least one certificate
+ * valid in the keystore
+ *
+ * At least one certificate from each Certificate Array
+ * of the Jar file must be found in the known Certificates
+ */
+ private void verifyAuthentication() throws CoreException {
+
+ CertificatePair[] entries = result.getRootCertificates();
+ boolean certificateFound = false;
+
+ // If all the certificate of an entry are
+ // not found in the list of known certifcate
+ // the certificate is not trusted by any keystore.
+ for (int i = 0; i < entries.length; i++) {
+ certificateFound = existsInKeystore(entries[i].getRoot());
+ if (certificateFound) {
+ result.setVerificationCode(IVerificationResult.TYPE_ENTRY_SIGNED_RECOGNIZED);
+ result.setFoundCertificate(entries[i]);
+ return;
+ }
+ }
+ }
+
+ /*
+ * Verifies the integrity of the JAR
+ */
+ private void verifyIntegrity(String file, String identifier) {
+
+ JarFile jarFile = null;
+
+ try {
+ // If the JAR is signed and not valid
+ // a security exception will be thrown
+ // while reading it
+ jarFile = new JarFile(file, true);
+ List filesInJar = readJarFile(jarFile, identifier);
+
+ // you have to read all the files once
+ // before getting the certificates
+ if (jarFile.getManifest() != null) {
+ Iterator iter = filesInJar.iterator();
+ boolean certificateFound = false;
+ while (iter.hasNext()) {
+ JarEntry currentJarEntry = (JarEntry) iter.next();
+ Certificate[] certs = currentJarEntry.getCertificates();
+ if ((certs != null) && (certs.length != 0)) {
+ certificateFound = true;
+ result.addCertificates(certs);
+ } else {
+ String jarEntryName = currentJarEntry.getName();
+ if (!jarEntryName.toUpperCase().startsWith(MANIFEST)
+ && !currentJarEntry.isDirectory()) {
+ // if the jarEntry is not in MANIFEST, consider the whole file unsigned
+ break;
+ }
+
+ }
+ }
+
+ if (certificateFound)
+ result.setVerificationCode(IVerificationResult.TYPE_ENTRY_SIGNED_UNRECOGNIZED);
+ else
+ result.setVerificationCode(IVerificationResult.TYPE_ENTRY_NOT_SIGNED);
+ } else {
+ Exception e = new Exception(NLS.bind(Messages.JarVerifier_InvalidFile, (new String[] { file })));
+ result.setResultException(e);
+ result.setVerificationCode(IVerificationResult.TYPE_ENTRY_NOT_SIGNED);
+ UpdateCore.warn(null,e);
+ }
+ } catch (SecurityException e) {
+ // Jar file is signed
+ // but content has changed since signed
+ result.setVerificationCode(IVerificationResult.TYPE_ENTRY_CORRUPTED);
+ } catch (InterruptedException e) {
+ result.setVerificationCode(IVerificationResult.VERIFICATION_CANCELLED);
+ } catch (Exception e) {
+ result.setVerificationCode(IVerificationResult.UNKNOWN_ERROR);
+ result.setResultException(e);
+ } finally {
+ if (jarFile!=null){
+ try {jarFile.close();} catch (IOException e){}
+ }
+ }
+
+ }
+
+ /*
+ *
+ */
+ private boolean alreadyValidated() {
+
+ if (result.getVerificationCode() == IVerificationResult.TYPE_ENTRY_NOT_SIGNED)
+ return (acceptUnsignedFiles);
+
+ if (getTrustedCertificates() != null) {
+ Iterator iter = getTrustedCertificates().iterator();
+ CertificatePair[] jarPairs = result.getRootCertificates();
+
+ // check if this is not a user accepted certificate for this feature
+ while (iter.hasNext()) {
+ CertificatePair trustedCertificate = (CertificatePair) iter.next();
+ for (int i = 0; i < jarPairs.length; i++) {
+ if (trustedCertificate.equals(jarPairs[i])) {
+ return true;
+ }
+ }
+ }
+
+ // if certificate pair not found in trusted add it for next time
+ for (int i = 0; i < jarPairs.length; i++) {
+ addTrustedCertificate(jarPairs[i]);
+ }
+ }
+
+ return false;
+ }
+
+ /*
+ *
+ */
+ private void addTrustedCertificate(CertificatePair pair) {
+ if (trustedCertificates == null)
+ trustedCertificates = new ArrayList();
+ if (pair != null)
+ trustedCertificates.add(pair);
+ }
+
+ /*
+ *
+ */
+ private List getTrustedCertificates() {
+ if (trustedCertificates == null)
+ trustedCertificates = new ArrayList();
+ return trustedCertificates;
+ }
+
+ /**
+ * @see IVerifier#setParent(IVerifier)
+ */
+ public void setParent(IVerifier parentVerifier) {
+ super.setParent(parentVerifier);
+ initialize();
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/KeyStores.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/KeyStores.java
new file mode 100644
index 0000000..9907ca6
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/KeyStores.java
@@ -0,0 +1,219 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.security;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.connection.ConnectionFactory;
+/**
+ * Class to manage the different KeyStores we should
+ * check for certificates of Signed JAR
+ */
+public class KeyStores {
+
+
+ /**
+ * java.policy files properties of the java.security file
+ */
+ private static final String JAVA_POLICY_URL = "policy.url."; //$NON-NLS-1$
+
+ /**
+ * Default keystore type in java.security file
+ */
+ private static final String DEFAULT_KEYSTORE_TYPE = "keystore.type"; //$NON-NLS-1$
+
+ /**
+ * List of KeystoreHandle pointing of valid KeyStores
+ * the URL of the KeystoreHandle is not tested yet...
+ */
+ private List /* of KeystoreHandle */ listOfKeyStores;
+
+ /**
+ * Iterator
+ */
+ private Iterator iterator;
+ /**
+ * KeyStores constructor comment.
+ */
+ public KeyStores() {
+ super();
+ initializeDefaultKeyStores();
+ }
+ /**
+ *
+ */
+ private Iterator getIterator() {
+ if (iterator == null)
+ iterator = listOfKeyStores.iterator();
+ return iterator;
+ }
+ /**
+ * returns trus if there is more Keystores in the list
+ */
+ public boolean hasNext() {
+ return getIterator().hasNext();
+ }
+ /**
+ * populate the list of Keystores
+ * should be done with Dialog with Cancel/Skip button if
+ * the connection to the URL is down...
+ */
+ private void initializeDefaultKeyStores() {
+
+ listOfKeyStores = new ArrayList(5);
+
+ // get JRE cacerts
+ try {
+ URL url = new URL("file", null, 0, System.getProperty("java.home") + File.separator + "lib" + File.separator + "security" + File.separator + "cacerts"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ listOfKeyStores.add(new KeystoreHandle(url,Security.getProperty(DEFAULT_KEYSTORE_TYPE)));
+ }
+ catch (MalformedURLException e) {
+ // should not happen, hardcoded...
+ }
+
+ // get java.home .keystore
+ try {
+ URL url = new URL("file", null, 0, System.getProperty("user.home") + File.separator + ".keystore"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ listOfKeyStores.add(new KeystoreHandle(url,Security.getProperty(DEFAULT_KEYSTORE_TYPE)));
+ }
+ catch (MalformedURLException e) {
+ // should not happen, hardcoded...
+ }
+
+ // get KeyStores from policy files...
+ int index = 1;
+ String java_policy = Security.getProperty(JAVA_POLICY_URL+index);
+ while (java_policy!=null){
+ // retrieve keystore url from java.policy
+ // also retrieve keystore type
+ KeystoreHandle keystore = getKeystoreFromLocation(java_policy);
+ if (keystore!=null){
+ listOfKeyStores.add(keystore);
+ }
+ index++;
+ java_policy = Security.getProperty(JAVA_POLICY_URL+index);
+ }
+
+ }
+ /**
+ * returns the URL for the Next KeystoreHandle
+ */
+ public KeystoreHandle next() {
+ return (KeystoreHandle) getIterator().next();
+ }
+
+ /**
+ * retrieve the keystore from java.policy file
+ */
+ private KeystoreHandle getKeystoreFromLocation(String location){
+
+ InputStream in = null;
+ char[] buff = new char[4096];
+
+
+ int indexOf$ = location.indexOf("${"); //$NON-NLS-1$
+ int indexOfCurly = location.indexOf('}',indexOf$);
+ if (indexOf$!=-1 && indexOfCurly!=-1){
+ String prop = System.getProperty(location.substring(indexOf$+2,indexOfCurly));
+ String location2 = location.substring(0,indexOf$);
+ location2 += prop;
+ location2 += location.substring(indexOfCurly+1);
+ location = location2;
+ }
+
+
+ try {
+ URL url = new URL(location);
+ in = ConnectionFactory.get(url).getInputStream();
+ Reader reader = new InputStreamReader(in);
+ int result = reader.read(buff);
+ StringBuffer contentBuff = new StringBuffer();
+ while (result!=-1){
+ contentBuff.append(buff,0,result);
+ result = reader.read(buff);
+ }
+
+ if (contentBuff.length()>0){
+ String content = new String(contentBuff);
+ int indexOfKeystore = content.indexOf("keystore"); //$NON-NLS-1$
+ if (indexOfKeystore != -1){
+ int indexOfSemiColumn = content.indexOf(';',indexOfKeystore);
+ return getKeystoreFromString(content.substring(indexOfKeystore,indexOfSemiColumn),url);
+ }
+ }
+ } catch (MalformedURLException e){
+ log(e);
+ } catch (IOException e){
+ // url.openStream, reader.read (x2)
+ // only log, the keystore may not exist
+ log(e);
+ } finally {
+ if (in!=null){
+ try {
+ in.close();
+ } catch (IOException e){}
+ }
+ }
+ return null;
+ }
+
+ /**
+ * retrieve the keystore from java.policy file
+ */
+ private KeystoreHandle getKeystoreFromString(String content,URL rootURL){
+ KeystoreHandle handle = null;
+ String keyStoreType = Security.getProperty(DEFAULT_KEYSTORE_TYPE);
+
+
+ int indexOfSpace = content.indexOf(' ');
+ if (indexOfSpace==-1) return null;
+
+ int secondSpace = content.lastIndexOf(',');
+ if (secondSpace==-1) {
+ secondSpace = content.length();
+ } else {
+ keyStoreType = content.substring(secondSpace+1,content.length()).trim();
+ }
+
+ URL url = null;
+ try {
+ url = new URL(content.substring(indexOfSpace,secondSpace));
+ } catch (MalformedURLException e){
+ log(e);
+ // the url maybe relative
+ try {
+ url = new URL(rootURL,content.substring(indexOfSpace,secondSpace));
+ } catch (MalformedURLException e1){
+ log(e1);
+ }
+ }
+
+ if (url!=null)
+ handle = new KeystoreHandle(url,keyStoreType);
+
+ return handle;
+ }
+
+ private void log(Exception e){
+ UpdateCore.warn("Cannot retrieve a KeyStore",e); //$NON-NLS-1$
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/KeystoreHandle.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/KeystoreHandle.java
new file mode 100644
index 0000000..d1a7b29
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/security/KeystoreHandle.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.update.internal.security;
+
+import java.net.*;
+
+
+
+/**
+ * Manages a handle to a keystore
+ */
+public class KeystoreHandle {
+
+ private URL location;
+ private String type;
+
+ public KeystoreHandle(URL url, String type){
+ this.location = url;
+ this.type = type;
+ }
+
+ /**
+ * Gets the location.
+ * @return Returns a URL
+ */
+ public URL getLocation() {
+ return location;
+ }
+
+ /**
+ * Sets the location.
+ * @param location The location to set
+ */
+ public void setLocation(URL location) {
+ this.location = location;
+ }
+
+ /**
+ * Gets the type.
+ * @return Returns a String
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Sets the type.
+ * @param type The type to set
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/verifier/CertVerificationResult.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/verifier/CertVerificationResult.java
new file mode 100644
index 0000000..d8c3b9e
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/verifier/CertVerificationResult.java
@@ -0,0 +1,259 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.verifier;
+
+import java.security.Principal;
+import java.security.cert.*;
+import java.text.DateFormat;
+import java.util.Date;
+import org.eclipse.osgi.signedcontent.SignedContent;
+import org.eclipse.osgi.signedcontent.SignerInfo;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.Messages;
+
+/**
+ * Result of the service
+ */
+public class CertVerificationResult implements IVerificationResult {
+
+
+ private int resultCode;
+ private int verificationCode;
+ private Exception resultException;
+
+ private SignedContent signedContent;
+ private String signerInfo;
+ private String verifierInfo;
+ private ContentReference contentReference;
+ private IFeature feature;
+ private boolean featureVerification;
+ private boolean alreadySeen;
+
+ public CertVerificationResult() {
+ }
+
+ /*
+ *
+ */
+ public int getResultCode() {
+ return resultCode;
+ }
+
+ /*
+ *
+ */
+ public Exception getVerificationException() {
+ return resultException;
+ }
+
+ /*
+ *
+ */
+ public void setResultCode(int newResultCode) {
+ resultCode = newResultCode;
+ }
+
+ /*
+ *
+ */
+ public void setResultException(Exception newResultException) {
+ resultException = newResultException;
+ }
+
+ /*
+ *
+ */
+ public int getVerificationCode() {
+ return verificationCode;
+ }
+
+ /*
+ *
+ */
+ public void setVerificationCode(int verificationCode) {
+ this.verificationCode = verificationCode;
+ }
+
+ void setSignedContent(SignedContent signedContent) {
+ this.signedContent = signedContent;
+ }
+
+ public SignerInfo[] getSigners() {
+ return signedContent.getSignerInfos();
+ }
+
+ /*
+ * Initializes the signerInfo and the VerifierInfo from the Certificate Pair
+ */
+ private void initializeCertificates(){
+ X509Certificate certRoot = null;
+ X509Certificate certIssuer = null;
+ SignerInfo trustedSigner;
+ SignerInfo[] signers = getSigners();
+ if (signers.length == 0)
+ return;
+ trustedSigner = signers[0];
+ for (int i = 0; i < signers.length; i++) {
+ if (signers[i].isTrusted()) {
+ trustedSigner = signers[i];
+ break;
+ }
+ }
+ Certificate[] certs = trustedSigner.getCertificateChain();
+ if (certs == null || certs.length == 0)
+ return;
+ certRoot = (X509Certificate) certs[certs.length - 1];
+ certIssuer = (X509Certificate) certs[0];
+
+ StringBuffer strb = new StringBuffer();
+ strb.append(issuerString(certIssuer.getSubjectDN()));
+ strb.append("\r\n"); //$NON-NLS-1$
+ strb.append(NLS.bind(Messages.JarVerificationResult_ValidBetween, (new String[] { dateString(certIssuer.getNotBefore()), dateString(certIssuer.getNotAfter()) })));
+ strb.append(checkValidity(trustedSigner));
+ signerInfo = strb.toString();
+ if (certIssuer != null && !certIssuer.equals(certRoot)) {
+ strb = new StringBuffer();
+ strb.append(issuerString(certIssuer.getIssuerDN()));
+ strb.append("\r\n"); //$NON-NLS-1$
+ strb.append(NLS.bind(Messages.JarVerificationResult_ValidBetween, (new String[] { dateString(certRoot.getNotBefore()), dateString(certRoot.getNotAfter()) })));
+ verifierInfo = strb.toString();
+ }
+
+ }
+
+ /*
+ * Returns a String to show if the certificate is valid
+ */
+ private String checkValidity(SignerInfo signer) {
+
+ try {
+ signedContent.checkValidity(signer);
+ } catch (CertificateExpiredException e) {
+ return ("\r\n" + Messages.JarVerificationResult_ExpiredCertificate); //$NON-NLS-1$
+ } catch (CertificateNotYetValidException e) {
+ return ("\r\n" + Messages.JarVerificationResult_CertificateNotYetValid); //$NON-NLS-1$
+ }
+ return ("\r\n" + Messages.JarVerificationResult_CertificateValid); //$NON-NLS-1$
+ }
+
+ /*
+ * Returns the label String from a X50name
+ */
+ private String issuerString(Principal principal) {
+// 19902
+// try {
+// if (principal instanceof X500Name) {
+// StringBuffer buf = new StringBuffer();
+// X500Name name = (X500Name) principal;
+// buf.append((name.getDNQualifier() != null) ? name.getDNQualifier() + ", " : "");
+// buf.append(name.getCommonName());
+// buf.append((name.getOrganizationalUnit() != null) ? ", " + name.getOrganizationalUnit() : "");
+// buf.append((name.getOrganization() != null) ? ", " + name.getOrganization() : "");
+// buf.append((name.getLocality() != null) ? ", " + name.getLocality() : "");
+// buf.append((name.getCountry() != null) ? ", " + name.getCountry() : "");
+// return new String(buf);
+// }
+// } catch (Exception e) {
+// UpdateCore.warn("Error parsing X500 Certificate",e);
+// }
+ return principal.toString();
+ }
+
+ /*
+ *
+ */
+ private String dateString(Date date) {
+ return DateFormat.getDateInstance().format(date);
+ }
+
+ /*
+ *
+ */
+ public String getSignerInfo() {
+ if (signerInfo==null) initializeCertificates();
+ return signerInfo;
+ }
+
+ /*
+ *
+ */
+ public String getVerifierInfo() {
+ if (signerInfo==null) initializeCertificates();
+ return verifierInfo;
+ }
+
+ /*
+ *
+ */
+ public ContentReference getContentReference() {
+ return contentReference;
+ }
+
+ /*
+ *
+ */
+ public void setContentReference(ContentReference ref) {
+ this.contentReference = ref;
+ }
+
+
+ /*
+ *
+ */
+ public IFeature getFeature() {
+ return feature;
+ }
+
+ /*
+ *
+ */
+ public void setFeature(IFeature feature) {
+ this.feature = feature;
+ }
+
+ /*
+ *
+ */
+ public String getText() {
+ return null;
+ }
+
+
+ /*
+ *
+ */
+ public boolean isFeatureVerification() {
+ return featureVerification;
+ }
+
+ /*
+ *
+ */
+ public void isFeatureVerification(boolean featureVerification) {
+ this.featureVerification = featureVerification;
+ }
+
+ /*
+ *
+ */
+ public boolean alreadySeen() {
+ return alreadySeen;
+ }
+
+ /*
+ *
+ */
+ public boolean alreadySeen(boolean seen) {
+ return this.alreadySeen = seen;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/verifier/CertVerifier.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/verifier/CertVerifier.java
new file mode 100644
index 0000000..50c8440
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/verifier/CertVerifier.java
@@ -0,0 +1,271 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.update.internal.verifier;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.jar.JarFile;
+import java.util.zip.ZipException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.signedcontent.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+
+/**
+ * The JarVerifier will check the integrity of the JAR.
+ * If the Jar is signed and the integrity is validated,
+ * it will check if one of the certificate of each file
+ * is in one of the keystore.
+ *
+ */
+
+public class CertVerifier extends Verifier {
+
+ private CertVerificationResult result;
+ private boolean acceptUnsignedFiles;
+ private IProgressMonitor monitor;
+ private File jarFile;
+ private SignedContentFactory factory;
+ private List trustedSignerInfos;
+
+ /*
+ * Default Constructor
+ */
+ public CertVerifier(SignedContentFactory factory) {
+ this.factory = factory;
+ initialize();
+ }
+
+
+ /*
+ *
+ */
+ private void initialize() {
+ result = null;
+ acceptUnsignedFiles = false;
+ }
+
+ /*
+ * init
+ */
+ private void init(IFeature feature, ContentReference contentRef) throws CoreException {
+ jarFile = null;
+ if (contentRef instanceof JarContentReference) {
+ JarContentReference jarReference = (JarContentReference) contentRef;
+ try {
+ jarFile = jarReference.asFile();
+ if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL)
+ UpdateCore.debug("Attempting to read JAR file:"+jarFile); //$NON-NLS-1$
+
+ // # of entries
+ if (!jarFile.exists()) throw new IOException();
+ JarFile jar = new JarFile(jarFile);
+ if (jar !=null){
+ try {
+ jar.close();
+ } catch (IOException ex) {
+ // unchecked
+ }
+ }
+ } catch (ZipException e){
+ throw Utilities.newCoreException(NLS.bind(Messages.JarVerifier_InvalidJar, (new String[] { jarReference.toString() })), e);
+ } catch (IOException e) {
+ throw Utilities.newCoreException(NLS.bind(Messages.JarVerifier_UnableToAccessJar, (new String[] { jarReference.toString() })), e);
+ }
+ }
+
+ result = new CertVerificationResult();
+ result.setVerificationCode(IVerificationResult.UNKNOWN_ERROR);
+ result.setResultException(null);
+ result.setFeature(feature);
+ result.setContentReference(contentRef);
+ }
+
+ /*
+ * @param newMonitor org.eclipse.core.runtime.IProgressMonitor
+ */
+ private void setMonitor(IProgressMonitor newMonitor) {
+ monitor = newMonitor;
+ }
+
+ /*
+ * @see IVerifier#verify(IFeature,ContentReference,boolean, InstallMonitor)
+ */
+ public IVerificationResult verify(
+ IFeature feature,
+ ContentReference reference,
+ boolean isFeatureVerification,
+ InstallMonitor monitor)
+ throws CoreException {
+
+ if (reference == null)
+ return result;
+
+ // if parent knows how to verify, ask the parent first
+ if (getParent() != null) {
+ IVerificationResult vr =
+ getParent().verify(feature, reference, isFeatureVerification, monitor);
+ if (vr.getVerificationCode() != IVerificationResult.TYPE_ENTRY_UNRECOGNIZED)
+ return vr;
+ }
+
+ // the parent couldn't verify
+ setMonitor(monitor);
+ init(feature, reference);
+ result.isFeatureVerification(isFeatureVerification);
+
+ if (jarFile!=null) {
+ result = verify(jarFile.getAbsolutePath(), reference.getIdentifier());
+ } else {
+ result.setVerificationCode(IVerificationResult.TYPE_ENTRY_UNRECOGNIZED);
+ }
+
+ return result;
+ }
+
+ /*
+ *
+ */
+ private CertVerificationResult verify(String file, String identifier) {
+
+ try {
+ SignedContent verifier = factory.getSignedContent(new File(file));
+ // verify integrity
+ verifyIntegrity(verifier, identifier);
+
+ //if user already said yes
+ result.alreadySeen(alreadyValidated());
+
+ // save the fact the file is not signed, so the user will not be prompted again
+ if (result.getVerificationCode()
+ == IVerificationResult.TYPE_ENTRY_NOT_SIGNED) {
+ acceptUnsignedFiles = true;
+ }
+
+ } catch (Exception e) {
+ result.setVerificationCode(IVerificationResult.UNKNOWN_ERROR);
+ result.setResultException(e);
+ }
+
+ if (monitor != null) {
+ monitor.worked(1);
+ if (monitor.isCanceled()) {
+ result.setVerificationCode(IVerificationResult.VERIFICATION_CANCELLED);
+ }
+ }
+
+ return result;
+ }
+
+ /*
+ * Verifies the integrity of the JAR
+ */
+ private void verifyIntegrity(SignedContent verifier, String identifier) {
+ try {
+ if (verifier.isSigned()) {
+ // If the JAR is signed and invalid then mark as corrupted
+ if (hasValidContent(verifier.getSignedEntries())) {
+ result.setSignedContent(verifier);
+ SignerInfo[] signers = verifier.getSignerInfos();
+ for (int i = 0; i < signers.length; i++)
+ if (signers[i].isTrusted()) {
+ result.setVerificationCode(IVerificationResult.TYPE_ENTRY_SIGNED_RECOGNIZED);
+ break;
+ }
+ if (result.getVerificationCode() != IVerificationResult.TYPE_ENTRY_SIGNED_RECOGNIZED)
+ result.setVerificationCode(IVerificationResult.TYPE_ENTRY_SIGNED_UNRECOGNIZED);
+ } else
+ result.setVerificationCode(IVerificationResult.TYPE_ENTRY_CORRUPTED);
+ } else {
+ result.setVerificationCode(IVerificationResult.TYPE_ENTRY_NOT_SIGNED);
+ return;
+ }
+ } catch (Exception e) {
+ result.setVerificationCode(IVerificationResult.UNKNOWN_ERROR);
+ result.setResultException(e);
+ }
+ }
+
+ private boolean hasValidContent(SignedContentEntry[] signedEntries) {
+ try {
+ for (int i = 0; i < signedEntries.length; i++)
+ signedEntries[i].verify();
+ } catch (InvalidContentException e) {
+ return false;
+ } catch (IOException e) {
+ return false;
+ }
+ return true;
+ }
+
+
+ /*
+ *
+ */
+ private boolean alreadyValidated() {
+ int verifyCode = result.getVerificationCode();
+ if (verifyCode == IVerificationResult.TYPE_ENTRY_NOT_SIGNED)
+ return (acceptUnsignedFiles);
+ if (verifyCode == IVerificationResult.UNKNOWN_ERROR)
+ return false;
+ if (result.getSigners() != null) { //getTrustedCertificates() can't be null as it is lazy initialized
+ Iterator iter = getTrustedInfos().iterator();
+ SignerInfo[] signers = result.getSigners();
+
+ // check if this is not a user accepted certificate for this feature
+ while (iter.hasNext()) {
+ SignerInfo chain = (SignerInfo) iter.next();
+ for (int i = 0; i < signers.length; i++)
+ if (chain.equals(signers[i]))
+ return true;
+ }
+
+ // if certificate pair not found in trusted add it for next time
+ for (int i = 0; i < signers.length; i++) {
+ addTrustedSignerInfo(signers[i]);
+ }
+ }
+
+ return false;
+ }
+
+ /*
+ *
+ */
+ private void addTrustedSignerInfo(SignerInfo signer) {
+ if (trustedSignerInfos == null)
+ trustedSignerInfos = new ArrayList();
+ if (signer != null)
+ trustedSignerInfos.add(signer);
+ }
+
+ /*
+ *
+ */
+ private List getTrustedInfos() {
+ if (trustedSignerInfos == null)
+ trustedSignerInfos = new ArrayList();
+ return trustedSignerInfos;
+ }
+
+ /**
+ * @see IVerifier#setParent(IVerifier)
+ */
+ public void setParent(IVerifier parentVerifier) {
+ super.setParent(parentVerifier);
+ initialize();
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IBatchOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IBatchOperation.java
new file mode 100644
index 0000000..db561f2
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IBatchOperation.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.update.operations;
+
+/**
+ * A batch operation is needed to execute a group of feature operations, such as installing a set of features.
+ * In fact, for installing features, it is recommended to wrap individual feature install operations as a
+ * batch operation, to ensure proper validation and configuration saving.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IBatchOperation extends IOperation {
+ /**
+ * Returns the batched operations.
+ * @return the batched operations
+ */
+ public abstract IFeatureOperation[] getOperations();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IConfigFeatureOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IConfigFeatureOperation.java
new file mode 100644
index 0000000..4b5fcb2
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IConfigFeatureOperation.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.update.operations;
+
+/**
+ * Operation that enables a feature in a configuration.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+*/
+public interface IConfigFeatureOperation extends IFeatureOperation {
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IFeatureOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IFeatureOperation.java
new file mode 100644
index 0000000..69ab740
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IFeatureOperation.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.update.operations;
+
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+
+/**
+ * An operation that applies to a feature, such as install, uninstall, etc.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IFeatureOperation extends IOperation {
+ /**
+ * Returns the feature to operate on.
+ * @return the feature to operate on.
+ */
+ public abstract IFeature getFeature();
+ /**
+ * Returns the site in which the operation is applied.
+ * @return the site that owns or will own the feature.
+ */
+ public abstract IConfiguredSite getTargetSite();
+ /**
+ * Returns the previous version of the feature (if any).
+ * @return the previous installed version of a feature (if any).
+ */
+ public abstract IFeature getOldFeature();
+ /**
+ * Sets the site in which the feature is being operated on.
+ * @param targetSite the site in which the featre is being operated on.
+ */
+ public abstract void setTargetSite(IConfiguredSite targetSite);
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IInstallFeatureOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IInstallFeatureOperation.java
new file mode 100644
index 0000000..c946349
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IInstallFeatureOperation.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.update.operations;
+
+import org.eclipse.update.core.*;
+
+/**
+ * An installation operation. This operation should not be executed by itself, it should be
+ * aggregated into a IBatchOperation, together with other IInstallOperations, so that the
+ * validation checks are done on the group, not per installation job.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IInstallFeatureOperation extends IFeatureOperation {
+ /**
+ * If the feature includes optional features, thi method returns the list
+ * of optional features to be installed.
+ * @return the list of optional features to be installed.
+ */
+ public IFeatureReference[] getOptionalFeatures();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IOperation.java
new file mode 100644
index 0000000..161518a
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IOperation.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.update.operations;
+
+import java.lang.reflect.*;
+
+import org.eclipse.core.runtime.*;
+
+/**
+ * Base update manager operation.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IOperation {
+ /**
+ * Returns true when the operation has been processed.
+ * @return true when the operation completed.
+ */
+ public abstract boolean isProcessed();
+ /**
+ * Marks the operation as processed.
+ */
+ public abstract void markProcessed();
+ /**
+ * Executes operation.
+ * @param pm Progress monitor for the operation
+ * @param listener Operation listener
+ * @return true if operation was successful and a restart is needed.
+ * @throws CoreException
+ * @throws InvocationTargetException
+ */
+ public abstract boolean execute(IProgressMonitor pm, IOperationListener listener) throws CoreException, InvocationTargetException;
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IOperationFactory.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IOperationFactory.java
new file mode 100644
index 0000000..88d416f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IOperationFactory.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.update.operations;
+
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+
+/**
+ * A factory interface for creating operations.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IOperationFactory {
+ /**
+ * Creates an operation for configuring an installed feature in the specified site.
+ * @param targetSite site containing the feature to configure
+ * @param feature feature to be configured
+ * @return the configure operation
+ */
+ public IConfigFeatureOperation createConfigOperation(
+ IConfiguredSite targetSite,
+ IFeature feature);
+
+ /**
+ * Creates an operation for unconfiguring a feature
+ * @param targetSite site containing the feature to unconfigure
+ * @param feature feature to be unconfigured
+ * @return the unconfigure operation
+ */
+ public IUnconfigFeatureOperation createUnconfigOperation(
+ IConfiguredSite targetSite,
+ IFeature feature);
+
+ /**
+ * Creates an operation for installing a feature.
+ * @param targetSite site in which the feature is to be installed
+ * @param feature feature to be installed
+ * @param optionalFeatures optionally included features to be installed (if any)
+ * @param unconfiguredOptionalFeatures when installing optional features, some can be left unconfigured
+ * @param verifier operation verification listener
+ * @return the install operation
+ */
+ public IInstallFeatureOperation createInstallOperation(
+ IConfiguredSite targetSite,
+ IFeature feature,
+ IFeatureReference[] optionalFeatures,
+ IFeature[] unconfiguredOptionalFeatures,
+ IVerificationListener verifier);
+
+ /**
+ * Creates an operation to uninstall a feature
+ * @param targetSite site containing the feature to uninstall
+ * @param feature feature to be uninstalled
+ * @return the uninstall operation
+ */
+ public IUninstallFeatureOperation createUninstallOperation(
+ IConfiguredSite targetSite,
+ IFeature feature);
+
+ /**
+ * Creates an operation for replacing this feature by a previous version
+ * @param feature current feature
+ * @param anotherFeature the new feature to be swapped in
+ * @return the revert feature version operation
+ */
+ public IConfigFeatureOperation createReplaceFeatureVersionOperation(
+ IFeature feature,
+ IFeature anotherFeature);
+
+ /**
+ * Creates an operation for executing a set of feature operation in batch mode
+ * @param operations operation to execute in batch mode
+ * @return the batch operation
+ */
+ public IBatchOperation createBatchInstallOperation(IInstallFeatureOperation[] operations);
+
+ /**
+ * Creates ann operation to configure/unconfigure an installation site (also known as enable/disable site)
+ * @param site site to configure/unconfigure
+ * @return the toggle site operation
+ */
+ public IToggleSiteOperation createToggleSiteOperation(
+ IConfiguredSite site);
+
+
+ /**
+ * Creates an operation to revert to a previous installation configuration.
+ * @param config configuration to revert to
+ * @param problemHandler error handler
+ * @return the revert operation
+ */
+ public IRevertConfigurationOperation createRevertConfigurationOperation(
+ IInstallConfiguration config,
+ IProblemHandler problemHandler);
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IOperationListener.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IOperationListener.java
new file mode 100644
index 0000000..8d15625
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IOperationListener.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.update.operations;
+
+/**
+ * Listener for the operation lifecycle. This allows listeners to execute certain code before an operation
+ * starts, or after it completes.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IOperationListener {
+ /**
+ * May be called before an operation starts executing.
+ * @param operation operation to listen to
+ * @param data info specific to the operation
+ * @return not used
+ */
+ public boolean beforeExecute(IOperation operation, Object data);
+ /**
+ * May be called after an operation finishes executing.
+ * @param operation operation to listen to
+ * @param data info specific to the operation
+ * @return not used
+ */
+ public boolean afterExecute(IOperation operation, Object data);
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IOperationValidator.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IOperationValidator.java
new file mode 100644
index 0000000..31cf00b
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IOperationValidator.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.operations;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+
+/**
+ * This class contains various validation methods to be invoked before or during executing update manager
+ * operations.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IOperationValidator {
+
+ /**
+ * Called before performing install.
+ * @return the error status, or null if no errors
+ */
+ public IStatus validatePendingInstall(IFeature oldFeature, IFeature newFeature);
+
+ /**
+ * Called before performing operation.
+ * @return the error status, or null if no errors
+ */
+ public IStatus validatePendingConfig(IFeature feature);
+
+ /**
+ * Called before performing operation.
+ * @return the error status, or null if no errors
+ */
+ public IStatus validatePendingUnconfig(IFeature feature);
+
+ /**
+ * Called before performing operation.
+ * @return the error status, or null if no errors
+ */
+ public IStatus validatePendingReplaceVersion(IFeature feature, IFeature anotherFeature);
+
+ /**
+ * Called before doing a revert/ restore operation
+ * @return the error status, or null if no errors
+ */
+ public IStatus validatePendingRevert(IInstallConfiguration config);
+
+ /**
+ * Called by the UI before doing a batched processing of
+ * several pending changes.
+ * @return the error status, or null if no errors
+ */
+ public IStatus validatePendingChanges(IInstallFeatureOperation[] jobs);
+
+ /**
+ * Check the current state.
+ * @return the error status, or null if no errors
+ */
+ public IStatus validateCurrentState();
+
+ /**
+ * Checks if the platform configuration has been modified outside this program.
+ * @return the error status, or null if no errors
+ */
+ public IStatus validatePlatformConfigValid();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IReplaceFeatureVersionOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IReplaceFeatureVersionOperation.java
new file mode 100644
index 0000000..d52e5c4
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IReplaceFeatureVersionOperation.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.update.operations;
+
+/**
+ * Operation that replaces a current feature by another version.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IReplaceFeatureVersionOperation extends IFeatureOperation {
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IRevertConfigurationOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IRevertConfigurationOperation.java
new file mode 100644
index 0000000..90fabc9
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IRevertConfigurationOperation.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.operations;
+
+/**
+ * An operation in which the current configuration is replaced by a previous one.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IRevertConfigurationOperation extends IOperation {
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IToggleSiteOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IToggleSiteOperation.java
new file mode 100644
index 0000000..f85833b
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IToggleSiteOperation.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.operations;
+
+/**
+ * An operation in which the unconfigured/configured state of a site is toggled.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IToggleSiteOperation extends IOperation {
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IUnconfigFeatureOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IUnconfigFeatureOperation.java
new file mode 100644
index 0000000..53b88e3
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IUnconfigFeatureOperation.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.update.operations;
+
+/**
+ * An operation that disables (unconfigure) a feature in a site.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IUnconfigFeatureOperation extends IFeatureOperation {
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IUninstallFeatureOperation.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IUninstallFeatureOperation.java
new file mode 100644
index 0000000..f5c7080
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IUninstallFeatureOperation.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.update.operations;
+
+
+/**
+ * A feature uninstall operation. The feature is removed from the disk when uninstalled.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IUninstallFeatureOperation extends IFeatureOperation {
+ public final static String UNINSTALL = "uninstall"; //$NON-NLS-1$
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/IUpdateModelChangedListener.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IUpdateModelChangedListener.java
new file mode 100644
index 0000000..b9dbe91
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/IUpdateModelChangedListener.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.operations;
+
+/**
+ * Listener for update model changes.
+ * Usually, when features are installed, configured, etc.
+ * a GUI may need to update its state, so it will have to register
+ * with the OperationsManager for update events.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IUpdateModelChangedListener {
+ /**
+ * Called after a feature/site/etc. is added
+ * @param parent parent object
+ * @param children added children
+ */
+ public void objectsAdded(Object parent, Object [] children);
+ /**
+ * Called after a feature/site/etc. is removed.
+ * @param parent parent object
+ * @param children removed children
+ */
+ public void objectsRemoved(Object parent, Object [] children);
+ /**
+ * Called when there are changes to a site/feature/etc.
+ * @param object object that changed
+ * @param property object property that changed
+ */
+ public void objectChanged(Object object, String property);
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/OperationsManager.java b/update/org.eclipse.update.core/src/org/eclipse/update/operations/OperationsManager.java
new file mode 100644
index 0000000..50cff42
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/OperationsManager.java
@@ -0,0 +1,248 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.operations;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.configurator.*;
+import org.eclipse.update.internal.operations.*;
+
+/**
+ * Entry point for update manager operations. Use this class to obtain the factory that creates
+ * update manager operations, or to get the operation validator.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class OperationsManager {
+ private static IOperationValidator validator;
+ private static IOperationFactory operationFactory;
+ private static Vector listeners = new Vector();
+ private static Vector pendingOperations = new Vector();
+
+ private static boolean inProgress;
+
+ private OperationsManager() {
+ }
+
+ /**
+ * Each update operations must be created by the operation factory.
+ * Use this method to obtain the factory.
+ * @return returns the operation factory
+ */
+ public static IOperationFactory getOperationFactory() {
+ if (operationFactory == null)
+ operationFactory = new OperationFactory();
+ return operationFactory;
+ }
+
+ /**
+ * Check if the feature is the subject of an update operation such as install,
+ * configure, etc. and return it. Currently there can only be one pending
+ * operation on a feature.
+ * @param feature feature to check for pending operations
+ * @return pending operation if any, otherwise null.
+ */
+ public static IFeatureOperation findPendingOperation(IFeature feature) {
+ for (int i = 0; i < pendingOperations.size(); i++) {
+ IFeatureOperation operation =
+ (IFeatureOperation) pendingOperations.elementAt(i);
+ if (operation.getFeature().equals(feature))
+ return operation;
+ }
+ return null;
+ }
+
+ /**
+ * Register a pending operation.
+ * @param operation pending operation
+ */
+ public static void addPendingOperation(IOperation operation) {
+ pendingOperations.add(operation);
+ //fireObjectsAdded(this, new Object[] { change });
+ }
+
+ /**
+ * Unregister a pending operation.
+ * @param operation pending operation
+ */
+ public static void removePendingOperation(IOperation operation) {
+ pendingOperations.remove(operation);
+ //fireObjectsRemoved(this, new Object[] { change });
+ }
+
+ /**
+ * Adds a model changed listener.
+ * @param listener update model change listener
+ */
+ public static void addUpdateModelChangedListener(IUpdateModelChangedListener listener) {
+ if (!listeners.contains(listener))
+ listeners.add(listener);
+ }
+
+ /**
+ * Removes an model changed listener.
+ * @param listener update model change listener
+ */
+ public static void removeUpdateModelChangedListener(IUpdateModelChangedListener listener) {
+ if (listeners.contains(listener))
+ listeners.remove(listener);
+ }
+
+ /**
+ * Notifies model changed listeners when features/sites/etc. are added.
+ * @param parent parent object
+ * @param children children added
+ */
+ public static void fireObjectsAdded(Object parent, Object[] children) {
+ for (Iterator iter = listeners.iterator(); iter.hasNext();) {
+ IUpdateModelChangedListener listener =
+ (IUpdateModelChangedListener) iter.next();
+ listener.objectsAdded(parent, children);
+ }
+ }
+
+ /**
+ * Notifies model changed listeners when features/sites/etc are removed.
+ * @param parent parent object
+ * @param children children removed
+ */
+ public static void fireObjectsRemoved(Object parent, Object[] children) {
+ for (Iterator iter = listeners.iterator(); iter.hasNext();) {
+ IUpdateModelChangedListener listener =
+ (IUpdateModelChangedListener) iter.next();
+ listener.objectsRemoved(parent, children);
+ }
+ }
+
+ /**
+ * Notifies model changed listeners when features/sites/etc. have changed.
+ * @param object changed object
+ * @param property changed object property
+ */
+ public static void fireObjectChanged(Object object, String property) {
+ for (Iterator iter = listeners.iterator(); iter.hasNext();) {
+ IUpdateModelChangedListener listener =
+ (IUpdateModelChangedListener) iter.next();
+ listener.objectChanged(object, property);
+ }
+ }
+
+ /**
+ * Returns true when any of the install operations requires a license agreement.
+ * @param jobs features to install
+ * @return true when any of the features to install have a license
+ */
+ public static boolean hasSelectedJobsWithLicenses(IInstallFeatureOperation[] jobs) {
+ for (int i = 0; i < jobs.length; i++) {
+ if (UpdateUtils.hasLicense(jobs[i].getFeature()))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true when any of the features to install has optional features.
+ * @param jobs features to install
+ * @return true when any of the features has optional features
+ */
+ public static boolean hasSelectedJobsWithOptionalFeatures(IInstallFeatureOperation[] jobs) {
+ for (int i = 0; i < jobs.length; i++) {
+ if (UpdateUtils.hasOptionalFeatures(jobs[i].getFeature()))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the list of operations that need a license agreement.
+ * @param jobs features to install
+ * @return the list of operation that need a license agreement
+ */
+ public static IInstallFeatureOperation[] getSelectedJobsWithLicenses(IInstallFeatureOperation[] jobs) {
+ ArrayList list = new ArrayList();
+ for (int i = 0; i < jobs.length; i++) {
+ if (UpdateUtils.hasLicense(jobs[i].getFeature()))
+ list.add(jobs[i]);
+ }
+ return (IInstallFeatureOperation[]) list.toArray(
+ new IInstallFeatureOperation[list.size()]);
+ }
+
+ /**
+ * Returns the list of operations that have optional features to install.
+ * @param jobs features to install
+ * @return list of operations that have optional features to install
+ */
+ public static IInstallFeatureOperation[] getSelectedJobsWithOptionalFeatures(IInstallFeatureOperation[] jobs) {
+ ArrayList list = new ArrayList();
+ for (int i = 0; i < jobs.length; i++) {
+ if (UpdateUtils.hasOptionalFeatures(jobs[i].getFeature()))
+ list.add(jobs[i]);
+ }
+ return (IInstallFeatureOperation[]) list.toArray(
+ new IInstallFeatureOperation[list.size()]);
+ }
+
+ /**
+ * Sets whether any operations is in progress.
+ * @param inProgress true when operation is in progress
+ */
+ public static synchronized void setInProgress(boolean inProgress) {
+ OperationsManager.inProgress = inProgress;
+ }
+
+ /**
+ * Returns true when some operation is being executed, false otherwise.
+ * @return true when some operation execution is in progress, false otherwise
+ */
+ public static synchronized boolean isInProgress() {
+ return inProgress;
+ }
+
+ /**
+ * Returns the operations validator.
+ * @return the operation validator
+ */
+ public static IOperationValidator getValidator() {
+ if (validator == null)
+ validator = new OperationValidator();
+ return validator;
+ }
+
+ /**
+ * Sets a custom operation validator
+ * @param validator the custom validator
+ */
+ public static void setValidator(IOperationValidator validator) {
+ OperationsManager.validator = validator;
+ }
+
+ /**
+ * Applies the changes made to the current configuration.
+ * Care must be taken when using this method. Normally, if you install a new
+ * plugin it is safe to do it.
+ */
+ public static void applyChangesNow() {
+ ConfigurationActivator configurator = ConfigurationActivator.getConfigurator();
+ configurator.installBundles();
+ pendingOperations.clear();
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/operations/package.html b/update/org.eclipse.update.core/src/org/eclipse/update/operations/package.html
new file mode 100644
index 0000000..0588f6e
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/operations/package.html
@@ -0,0 +1,20 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="Author" content="IBM">
+ <meta name="GENERATOR" content="Mozilla/4.72 [en] (Windows NT 5.0; U) [Netscape]">
+ <title>Package-level Javadoc</title>
+</head>
+<body>
+Provides support for performing various install/update operations.
+<h2>
+Package Specification</h2>
+This package contains interfaces for performing update/install operations
+without using the Update Manager user interface.
+<p>
+<b>Note:</b> This package has been deprecated and will be deleted in a future
+release. See bug 311590 for details.
+</p>
+</body>
+</html>
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/BackLevelFilter.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/BackLevelFilter.java
new file mode 100644
index 0000000..b5c3dc0
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/BackLevelFilter.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.search;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.operations.*;
+
+/**
+ * This class can be added to the update search request
+ * to filter out features that are back-level (are
+ * older or the same as the features already installed).
+ *
+ * <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>
+ * @see UpdateSearchRequest
+ * @see IUpdateSearchFilter
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class BackLevelFilter extends BaseFilter {
+
+ public boolean accept(IFeature match) {
+
+ PluginVersionIdentifier matchVid = match.getVersionedIdentifier().getVersion();
+ IFeature [] installed = UpdateUtils.getInstalledFeatures(match.getVersionedIdentifier(), false);
+ if (installed.length==0) return true;
+
+ for (int i=0; i<installed.length; i++) {
+ PluginVersionIdentifier ivid = installed[i].getVersionedIdentifier().getVersion();
+ if (matchVid.isGreaterThan(ivid))
+ continue;
+ // installed version is the same or newer than
+ // the match - filter out
+ return false;
+ }
+ return true;
+
+ }
+
+ public boolean accept(IFeatureReference match) {
+ try {
+ PluginVersionIdentifier matchVid = match.getVersionedIdentifier().getVersion();
+ IFeature [] installed = UpdateUtils.getInstalledFeatures(match.getVersionedIdentifier(), false);
+ if (installed.length==0) return true;
+
+ for (int i=0; i<installed.length; i++) {
+ PluginVersionIdentifier ivid = installed[i].getVersionedIdentifier().getVersion();
+ if (matchVid.isGreaterThan(ivid))
+ continue;
+ // installed version is the same or newer than
+ // the match - filter out
+ return false;
+ }
+ return true;
+ } catch (CoreException e) {
+ return false;
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/BaseFilter.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/BaseFilter.java
new file mode 100644
index 0000000..1d374e1
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/BaseFilter.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.search;
+
+import org.eclipse.update.core.*;
+
+/**
+ * Base filter class
+ *
+ * <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>
+ * @see UpdateSearchRequest
+ * @see IUpdateSearchFilter
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class BaseFilter implements IUpdateSearchFilter {
+ /**
+ * @deprecated In 3.1 only the accept (IFeatureReference) will be used
+ */
+ public boolean accept(IFeature match) {
+ return true;
+ }
+ public boolean accept(IFeatureReference match) {
+ return true;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/EnvironmentFilter.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/EnvironmentFilter.java
new file mode 100644
index 0000000..f9aa1f6
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/EnvironmentFilter.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.search;
+
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.*;
+
+/**
+ * This class can be added to the update search request
+ * to filter out features that do not match the current
+ * environment settings.
+ *
+ * <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>
+ * @see UpdateSearchRequest
+ * @see IUpdateSearchFilter
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class EnvironmentFilter extends BaseFilter {
+
+ public boolean accept(IFeature match) {
+ return UpdateManagerUtils.isValidEnvironment(match);
+ }
+
+ public boolean accept(IFeatureReference match) {
+ return UpdateManagerUtils.isValidEnvironment(match);
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/IQueryUpdateSiteAdapter.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/IQueryUpdateSiteAdapter.java
new file mode 100644
index 0000000..c96ffa1
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/IQueryUpdateSiteAdapter.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.search;
+
+/**
+ * This interface is used for update site adapter used
+ * for specific query searches. It adds a mapping ID
+ * that can be used when mapping file is specified.
+ * If a matching mapping is found for this ID,
+ * the replacement URL found in the mapping file will be
+ * used instead of this adapter.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IQueryUpdateSiteAdapter extends IUpdateSiteAdapter {
+/**
+ * Returns an ID that can be used for matching against the information in the address mapping file.
+ * @return a mapping Id to compare against the address mapping file.
+ */
+ public String getMappingId();
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchCategory.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchCategory.java
new file mode 100644
index 0000000..f0a52e3
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchCategory.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.search;
+
+/**
+ * This interface is used to encapsulate a particular Update
+ * search pattern. Each search category is free to scan
+ * sites using a specific algorithm. Search category must
+ * have a unique ID. The actual search is performed in
+ * search queries. A category can provide one or more
+ * queries to run during the search.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IUpdateSearchCategory {
+/**
+ * Returns the unique identifier of this search category.
+ */
+ public String getId();
+/**
+ * Accepts the identifier assigned to this category during
+ * the registry reading.
+ */
+ public void setId(String id);
+
+/**
+ * Returns an array of update search queries that need to
+ * be run during the search.
+ * @return an arry of update search queries
+ */
+ IUpdateSearchQuery [] getQueries();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchFilter.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchFilter.java
new file mode 100644
index 0000000..68df1d5
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchFilter.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.search;
+
+import org.eclipse.update.core.*;
+
+/**
+ * Classes that implement this interface can be used to filter the
+ * results of the update search.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IUpdateSearchFilter {
+ /**
+ * Tests a feature according to this filter's criteria.
+ * @param match the feature to test
+ * @return <samp>true</samp> if the feature has been accepted, <samp>false</samp> otherwise.
+ * @deprecated In 3.1 only the accept (IFeatureReference) will be used
+ */
+ boolean accept(IFeature match);
+
+ /**
+ * Tests a feature reference according to this filter's criteria.
+ * This is a prefilter that allows rejecting a feature before a potentially lengthy download.
+ * @param match the feature reference to test
+ * @return <samp>true</samp> if the feature reference has been accepted, <samp>false</samp> otherwise.
+ */
+ boolean accept(IFeatureReference match);
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchQuery.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchQuery.java
new file mode 100644
index 0000000..23023e8
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchQuery.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.search;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+
+/**
+ * A search query.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IUpdateSearchQuery {
+/**
+ * Returns an update site adapter that should be added to the scope
+ * while running this query. Some search category may need to
+ * scan specific site adapter in addition to those specified in
+ * the search scope.
+ *
+ * @return the query-specific site adapter or <samp>null</samp> if
+ * not specified.
+ *
+ */
+ public IQueryUpdateSiteAdapter getQuerySearchSite();
+
+/**
+ * Executes the query. The implementors should scan the provided
+ * update site (skipping certain categories if provided) and
+ * pass the matches to the result collector. The query is also
+ * responsible for scoping and moving the provided progress monitor.
+ *
+ * @param site the update site to scan
+ * @param categoriesToSkip an array of category names that need to be skipped or <samp>null</samp> if categories should not be taken into account.
+ * @param filter a filter to apply before passing the match to collector
+ * @param collector an object that is used for reporting search results
+ * @param monitor a progress monitor to report search progress within the provided site
+ */
+ public void run(ISite site, String [] categoriesToSkip, IUpdateSearchFilter filter, IUpdateSearchResultCollector collector, IProgressMonitor monitor);
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchResultCollector.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchResultCollector.java
new file mode 100644
index 0000000..329c5cf
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchResultCollector.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.search;
+
+import org.eclipse.update.core.*;
+
+/**
+ * Search results are collected by implementing this interface
+ * and passing it to the search request. If the implementation is
+ * visual, it is recommended that the match is shown as soon
+ * as it is collected (rather than kept in a list and presented
+ * at the end of the search).
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IUpdateSearchResultCollector {
+/**
+ * Called when a matching feature has been found during
+ * the search.
+ * @param match the matching feature
+ */
+ void accept(IFeature match);
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchResultCollectorFromMirror.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchResultCollectorFromMirror.java
new file mode 100644
index 0000000..a69c790
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchResultCollectorFromMirror.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.update.search;
+
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.update.core.ISiteWithMirrors;
+import org.eclipse.update.core.IURLEntry;
+
+/**
+ * Search results are collected by implementing this interface
+ * and passing it to the search request. If the implementation is
+ * visual, it is recommended that the match is shown as soon
+ * as it is collected (rather than kept in a list and presented
+ * at the end of the search). This interface should be implemented
+ * when you want to support collection of results from a mirror site,
+ * otherwise you can just implement the IUpdateSearchResultsCollector.
+ * <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>
+ * @since 3.1
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IUpdateSearchResultCollectorFromMirror extends
+ IUpdateSearchResultCollector {
+
+ /**
+ * Returns a mirror of the specified site. Normally, if the site defines some mirrors,
+ * this method can be implement so that it prompts the user to pick one of the mirrors.
+ * @param site the site to get the mirror for
+ * @param siteName the name of the site
+ * @return a mirror (url+label) for the specified site, or null if no mirror is needed
+ * @throws OperationCanceledException if the user chooses to cancel
+ * the prompt instead of choosing the mirror from the list.
+ */
+ public IURLEntry getMirror(ISiteWithMirrors site, String siteName) throws OperationCanceledException;
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchSite.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchSite.java
new file mode 100644
index 0000000..e4b7fb7
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSearchSite.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.search;
+
+/**
+ * This interface is used to represent sites that need to be
+ * searched within the search scope. In addition to being an
+ * update site adapter, it also returns an array of categories
+ * within the site that need not be searched (skipping categories
+ * makes the search faster because fewer features need to
+ * be checked and potentially downloaded from the server).
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IUpdateSearchSite extends IUpdateSiteAdapter {
+/**
+ * Returns an array of categories that need not be searched
+ * when scanning this site or <samp>null</samp> if all the
+ * features must be tested.
+ * @return an array of category names or <samp>null</samp> if
+ * all the features must be tested.
+ */
+ String[] getCategoriesToSkip();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSiteAdapter.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSiteAdapter.java
new file mode 100644
index 0000000..d1539a8
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/IUpdateSiteAdapter.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.search;
+
+import java.net.*;
+
+/**
+ * This interface wraps an update site URL and adds
+ * a presentation label. It is used to encapsulate sites that need
+ * to be visited during the update search.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public interface IUpdateSiteAdapter {
+ /**
+ * Returns the presentation string that can be used
+ * for this site.
+ * @return the update site label
+ */
+ public String getLabel();
+ /**
+ * Returns the URL of the update site.
+ * @return the URL of the update site.
+ */
+ public URL getURL();
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/UpdateSearchRequest.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/UpdateSearchRequest.java
new file mode 100644
index 0000000..d5a7481
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/UpdateSearchRequest.java
@@ -0,0 +1,520 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.search;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.IFeatureReference;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.ISiteWithMirrors;
+import org.eclipse.update.core.IURLEntry;
+import org.eclipse.update.core.SiteManager;
+import org.eclipse.update.internal.core.ExtendedSite;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.operations.UpdateUtils;
+import org.eclipse.update.internal.search.SiteSearchCategory;
+import org.eclipse.update.internal.search.UpdatePolicy;
+import org.eclipse.update.internal.search.UpdateSiteAdapter;
+import org.eclipse.update.internal.search.UpdatesSearchCategory;
+
+/**
+ * This class is central to update search. The search pattern
+ * is encapsulated in update search category, while the search
+ * scope is defined in the scope object. When these two objects
+ * are defined and set, search can be performed using the
+ * provided method. Search results are reported to the
+ * result collector, while search progress is tracked using
+ * the progress monitor.
+ * <p>Classes that implement <samp>IUpdateSearchResultCollector</samp>
+ * should call 'accept' to test if the match should be
+ * accepted according to the filters added to the request.
+ *
+ * <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>
+ * @see UpdateSearchScope
+ * @see IUpdateSearchCategory
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class UpdateSearchRequest {
+ private IUpdateSearchCategory category;
+ private UpdateSearchScope scope;
+ private boolean searchInProgress = false;
+ private AggregateFilter aggregateFilter = new AggregateFilter();
+
+ private static class UpdateSearchSite
+ extends UpdateSiteAdapter
+ implements IUpdateSearchSite {
+ private String[] categoriesToSkip;
+
+ public UpdateSearchSite(
+ String label,
+ URL siteURL,
+ String[] categoriesToSkip) {
+ super(label, siteURL);
+ this.categoriesToSkip = categoriesToSkip;
+ }
+ public String[] getCategoriesToSkip() {
+ return categoriesToSkip;
+ }
+}
+
+ class MirroredUpdateSiteAdapter extends UpdateSiteAdapter {
+ public MirroredUpdateSiteAdapter(IURLEntry mirror) {
+ super(mirror.getAnnotation(), mirror.getURL());
+ }
+ }
+
+ class AggregateFilter implements IUpdateSearchFilter {
+ private ArrayList filters;
+ public void addFilter(IUpdateSearchFilter filter) {
+ if (filters == null)
+ filters = new ArrayList();
+ if (filters.contains(filter) == false)
+ filters.add(filter);
+ }
+
+ public void removeFilter(IUpdateSearchFilter filter) {
+ if (filters == null)
+ return;
+ filters.remove(filter);
+ }
+
+ /**
+ * @deprecated In 3.1 only the accept (IFeatureReference) will be used
+ */
+ public boolean accept(IFeature match) {
+ if (filters == null)
+ return true;
+ for (int i = 0; i < filters.size(); i++) {
+ IUpdateSearchFilter filter = (IUpdateSearchFilter) filters.get(i);
+ if (filter.accept(match) == false)
+ return false;
+ }
+ return true;
+ }
+
+ public boolean accept(IFeatureReference match) {
+ if (filters == null)
+ return true;
+ for (int i = 0; i < filters.size(); i++) {
+ IUpdateSearchFilter filter = (IUpdateSearchFilter) filters.get(i);
+ if (filter.accept(match) == false)
+ return false;
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Returns an updates search category for use in discovering updates
+ * to existing function on update sites.
+ *
+ * @return an updates search category
+ * @since 3.1
+ */
+ public static IUpdateSearchCategory createDefaultUpdatesSearchCategory() {
+ return new UpdatesSearchCategory();
+ }
+
+ /**
+ * Returns a site search category for use in discovering new function on update sites.
+ *
+ * @return a site search category
+ * @since 3.1
+ */
+ public static IUpdateSearchCategory createDefaultSiteSearchCategory() {
+ return new SiteSearchCategory();
+ }
+
+ /**
+ * The constructor that accepts the search category and
+ * scope objects.
+ * @param category the actual search pattern that should be applied
+ * @param scope a list of sites that need to be scanned during the search
+ */
+ public UpdateSearchRequest(
+ IUpdateSearchCategory category,
+ UpdateSearchScope scope) {
+ this.category = category;
+ this.scope = scope;
+ }
+ /**
+ * Returns the search catagory used in this request.
+ * @return the search category
+ */
+
+ public IUpdateSearchCategory getCategory() {
+ return category;
+ }
+
+ /**
+ * Returns the scope of this search request.
+ * @return search scope
+ */
+
+ public UpdateSearchScope getScope() {
+ return scope;
+ }
+ /**
+ * Adds a filter to this request. This method does nothing
+ * if search is alrady in progress.
+ * @param filter the filter
+ * @see UpdateSearchRequest#removeFilter
+ */
+ public void addFilter(IUpdateSearchFilter filter) {
+ if (searchInProgress)
+ return;
+ aggregateFilter.addFilter(filter);
+ }
+ /**
+ * Removes the filter from this request. This method does
+ * nothing if search is alrady in progress.
+ * @param filter the filter to remove
+ * @see UpdateSearchRequest#addFilter
+ */
+
+ public void removeFilter(IUpdateSearchFilter filter) {
+ if (searchInProgress)
+ return;
+ aggregateFilter.removeFilter(filter);
+ }
+
+ /**
+ * Sets the scope object. It is possible to reuse the search request
+ * object by modifying the scope and re-running the search.
+ * @param scope the new search scope
+ */
+ public void setScope(UpdateSearchScope scope) {
+ this.scope = scope;
+ }
+ /**
+ * Tests whether this search request is current running.
+ * @return <samp>true</samp> if the search is currently running, <samp>false</samp> otherwise.
+ */
+ public boolean isSearchInProgress() {
+ return searchInProgress;
+ }
+
+ /**
+ * Runs the search using the category and scope configured into
+ * this request. As results arrive, they are passed to the
+ * search result collector object.
+ * @param collector matched features are passed to this object
+ * @param monitor used to track the search progress
+ * @throws CoreException
+ */
+ public void performSearch(
+ IUpdateSearchResultCollector collector,
+ IProgressMonitor monitor)
+ throws CoreException, OperationCanceledException {
+
+ ArrayList statusList = new ArrayList();
+
+ searchInProgress = true;
+ IUpdateSearchQuery[] queries = category.getQueries();
+ IUpdateSearchSite[] candidates = scope.getSearchSites();
+ Set visitedSitesURL = new HashSet();
+ Set visitedSites = new HashSet();
+ for(int i = 0; i < candidates.length; i++) {
+ visitedSitesURL.add(candidates[i].getURL());
+ //visitedSites.add(candidates[i]);
+ }
+ URL updateMapURL = scope.getUpdateMapURL();
+ boolean searchFeatureProvidedSites = scope.isFeatureProvidedSitesEnabled();
+
+ if (!monitor.isCanceled()) {
+
+ int nsearchsites = 0;
+ try {
+ for (int i = 0; i < queries.length; i++) {
+ if (queries[i].getQuerySearchSite() != null)
+ nsearchsites++;
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+
+ }
+
+ int ntasks = nsearchsites + queries.length * candidates.length;
+ if (updateMapURL!=null) ntasks++;
+
+ monitor.beginTask(Messages.UpdateSearchRequest_searching, ntasks);
+
+ try {
+ UpdatePolicy updatePolicy=null;
+ if (updateMapURL!=null) {
+ updatePolicy = new UpdatePolicy();
+ IStatus status =UpdateUtils.loadUpdatePolicy(updatePolicy, updateMapURL, new SubProgressMonitor(monitor, 1));
+ if (status != null)
+ statusList.add(status);
+ }
+
+ List combinedAssociateSites = new ArrayList();
+ for (int i = 0; i < queries.length; i++) {
+ IUpdateSearchQuery query = queries[i];
+ IQueryUpdateSiteAdapter qsite = query.getQuerySearchSite();
+ // currently, the next conditional is only executed (qsite!=null) when
+ // running an update search.
+ if (qsite != null && searchFeatureProvidedSites) {
+ // do not update features that are installed in read-only locations
+ if (query instanceof UpdatesSearchCategory.UpdateQuery) {
+ IFeature feature = ((UpdatesSearchCategory.UpdateQuery)query).getFeature();
+ if (feature != null && !feature.getSite().getCurrentConfiguredSite().verifyUpdatableStatus().isOK())
+ continue;
+ }
+ // check for mapping
+ IUpdateSiteAdapter mappedSite = getMappedSite(updatePolicy, qsite);
+ // when there is no mapped site the feature is not updatable
+ if (mappedSite == null || mappedSite.getURL() == null)
+ continue;
+ SubProgressMonitor subMonitor =
+ new SubProgressMonitor(monitor, 1);
+ List associateSites = new ArrayList();
+ IStatus status =
+ searchOneSite(
+ mappedSite,
+ null,
+ query,
+ collector,
+ associateSites,
+ subMonitor,
+ true);
+ if (status != null)
+ statusList.add(status);
+ if (monitor.isCanceled())
+ break;
+ combinedAssociateSites = combineAssociateSites( combinedAssociateSites, associateSites, visitedSitesURL, visitedSites);
+ }
+
+ for (int j = 0; j < candidates.length; j++) {
+ if (monitor.isCanceled()) {
+ break;
+ }
+ IUpdateSearchSite source = candidates[j];
+ SubProgressMonitor subMonitor =
+ new SubProgressMonitor(monitor, 1);
+ List associateSites = new ArrayList();
+ IStatus status =
+ searchOneSite(
+ source,
+ source.getCategoriesToSkip(),
+ query,
+ collector,
+ associateSites,
+ subMonitor,
+ true);
+ if (status != null)
+ statusList.add(status);
+ combinedAssociateSites = combineAssociateSites( combinedAssociateSites, associateSites, visitedSitesURL, visitedSites);
+ }
+ if (monitor.isCanceled())
+ break;
+
+
+ for(int associateSitesDepth = 0; associateSitesDepth < 5; associateSitesDepth++) {
+ List tempCombinedSites = new ArrayList();
+ Iterator combinedAssociateSitesIterator = combinedAssociateSites.iterator();
+ while(combinedAssociateSitesIterator.hasNext()) {
+
+ IUpdateSearchSite source = (IUpdateSearchSite)combinedAssociateSitesIterator.next();
+
+ List associateSites = new ArrayList();
+ SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, 1);
+ IStatus status =
+ searchOneSite(
+ source,
+ source.getCategoriesToSkip(),
+ query,
+ collector,
+ associateSites,
+ subMonitor,
+ true);
+ combinedAssociateSites = combineAssociateSites( tempCombinedSites, associateSites, visitedSitesURL, visitedSites);
+ if (status != null)
+ statusList.add(status);
+ }
+ combinedAssociateSites = tempCombinedSites;
+
+ }
+ if (monitor.isCanceled())
+ break;
+ }
+ } catch (CoreException e) {
+ searchInProgress = false;
+ monitor.done();
+ throw e;
+ }
+ }
+ searchInProgress = false;
+ monitor.done();
+
+
+ Iterator visitedSitesIterator = visitedSites.iterator();
+ while (visitedSitesIterator.hasNext()) {
+ IUpdateSearchSite associateSite = (IUpdateSearchSite)visitedSitesIterator.next();
+ scope.addSearchSite(associateSite.getLabel(), associateSite.getURL(), null);
+ }
+ if (statusList.size() > 0) {
+ if (statusList.size()==1 && ((IStatus)statusList.get(0)).getSeverity()==IStatus.CANCEL)
+ throw new OperationCanceledException();
+ IStatus[] children =
+ (IStatus[]) statusList.toArray(new IStatus[statusList.size()]);
+ MultiStatus multiStatus =
+ new MultiStatus(
+ "org.eclipse.update.core", //$NON-NLS-1$
+ ISite.SITE_ACCESS_EXCEPTION,
+ children,
+ Messages.Search_networkProblems,
+ null);
+
+ throw new CoreException(multiStatus);
+ }
+ }
+
+
+ private List combineAssociateSites(List combinedAssociateSites, List associateSites, Set visitedSitesURL, Set visitedSites) {
+ Iterator iterator = associateSites.iterator();
+
+ while(iterator.hasNext()) {
+ UpdateSearchSite associateSite = (UpdateSearchSite)iterator.next();
+ if ( !visitedSitesURL.contains(associateSite.getURL())) {
+ combinedAssociateSites.add(associateSite);
+ visitedSitesURL.add(associateSite.getURL());
+ visitedSites.add(associateSite);
+ }
+
+ }
+ return combinedAssociateSites;
+ }
+
+
+/*
+ * See if this query site adapter is mapped in the map file
+ * to a different URL.
+ */
+ private IUpdateSiteAdapter getMappedSite(UpdatePolicy policy, IQueryUpdateSiteAdapter qsite) {
+ if (policy!=null && policy.isLoaded()) {
+ IUpdateSiteAdapter mappedSite = policy.getMappedSite(qsite.getMappingId());
+ if (mappedSite!=null)
+ return mappedSite;
+ else // no match - use original site if fallback allowed, or nothing.
+ return policy.isFallbackAllowed()? qsite : null;
+ }
+ return qsite;
+ }
+
+/*
+ * Search one site using the provided query.
+ */
+ private IStatus searchOneSite(
+ IUpdateSiteAdapter siteAdapter,
+ String[] categoriesToSkip,
+ IUpdateSearchQuery query,
+ IUpdateSearchResultCollector collector,
+ List associateSites,
+ SubProgressMonitor monitor,
+ boolean checkMirrors)
+ throws CoreException {
+
+ String text = NLS.bind(Messages.UpdateSearchRequest_contacting, siteAdapter.getLabel());
+ monitor.subTask(text);
+ monitor.beginTask("", 10); //$NON-NLS-1$
+ URL siteURL = siteAdapter.getURL();
+
+ ISite site;
+ try {
+ site =
+ SiteManager.getSite(
+ siteURL,
+ new SubProgressMonitor(monitor, 1));
+
+ // If frozen connection was canceled, there will be no site.
+ if (site == null) {
+ monitor.worked(9);
+ return null;
+ }
+
+
+ // prompt the user to pick up a site (do not recursively go into mirror sites on the mirror site)
+ if ((collector instanceof IUpdateSearchResultCollectorFromMirror) &&
+ (site instanceof ISiteWithMirrors) &&
+ !(siteAdapter instanceof MirroredUpdateSiteAdapter)) {
+
+ IURLEntry mirror = null;
+ try {
+ mirror = ((IUpdateSearchResultCollectorFromMirror)collector).getMirror((ISiteWithMirrors)site, siteAdapter.getLabel());
+ if (site instanceof ExtendedSite) {
+ ((ExtendedSite)site).setSelectedMirror(mirror);
+ }
+ }
+ catch (OperationCanceledException e) {
+ monitor.setCanceled(true);
+ return Status.CANCEL_STATUS;
+ }
+
+ if (mirror != null)
+ return searchOneSite(new MirroredUpdateSiteAdapter(mirror), categoriesToSkip, query, collector, associateSites, new SubProgressMonitor(monitor,1), false);
+ }
+ } catch (CoreException e) {
+ // Test the exception. If the exception is
+ // due to the site connection problems,
+ // allow the search to move on to
+ // the next site. Otherwise,
+ // rethrow the exception, causing the search
+ // to terminate.
+ IStatus status = e.getStatus();
+ if (status == null)
+// || status.getCode() != ISite.SITE_ACCESS_EXCEPTION)
+ throw e;
+ monitor.worked(10);
+ return status;
+ }
+
+ text = NLS.bind(Messages.UpdateSearchRequest_checking, siteAdapter.getLabel());
+ monitor.getWrappedProgressMonitor().subTask(text);
+
+ if (site instanceof ExtendedSite) {
+ //System.out.println("ExtendedSite is here"); //$NON-NLS-1$
+ IURLEntry[] associateSitesList = ((ExtendedSite)site).getAssociateSites();
+ if (associateSitesList != null) {
+ for(int i = 0; i < associateSitesList.length; i++) {
+ associateSites.add(new UpdateSearchSite(associateSitesList[i].getAnnotation(), associateSitesList[i].getURL(), null));
+ }
+ }
+ }
+ query.run(
+ site,
+ categoriesToSkip,
+ aggregateFilter,
+ collector,
+ new SubProgressMonitor(monitor, 9));
+ return null;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/UpdateSearchScope.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/UpdateSearchScope.java
new file mode 100644
index 0000000..13f56f2
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/UpdateSearchScope.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.search;
+
+import java.net.*;
+import java.util.Vector;
+
+import org.eclipse.update.internal.search.*;
+
+/**
+ * This class encapsulates update scope of the update search.
+ * Sites that need to be visited should be added to the scope.
+ * If some categories should be skipped, their names must be
+ * passed as array of strings to the method.
+ *
+ * <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>
+ * @see UpdateSearchRequest
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class UpdateSearchScope {
+ private Vector sites;
+ private URL updateMapURL;
+ private boolean isFeatureProvidedSitesEnabled = true;
+
+ private static class UpdateSearchSite
+ extends UpdateSiteAdapter
+ implements IUpdateSearchSite {
+ private String[] categoriesToSkip;
+
+ public UpdateSearchSite(
+ String label,
+ URL siteURL,
+ String[] categoriesToSkip) {
+ super(label, siteURL);
+ this.categoriesToSkip = categoriesToSkip;
+ }
+ public String[] getCategoriesToSkip() {
+ return categoriesToSkip;
+ }
+ }
+
+ /**
+ * The default constructor.
+ */
+ public UpdateSearchScope() {
+ sites = new Vector();
+ }
+
+ /**
+ * Sets the optional URL of the update map file. This file
+ * is used to redirect search for new updates to other
+ * servers and is typically used when a local
+ * update site proxy (possibly behind the firewall) is
+ * set up.
+ * @param url the url of the Java properties file that
+ * contains the redirection information.
+ */
+
+ public void setUpdateMapURL(URL url) {
+ this.updateMapURL = url;
+ }
+
+ /**
+ * Returns the optional URL of the update map file. By
+ * default, no map file is set.
+ * @return the URL of the map file or <samp>null</samp>
+ * if not set.
+ */
+
+ public URL getUpdateMapURL() {
+ return updateMapURL;
+ }
+
+ /**
+ * Adds the site to scan to the search scope.
+ * @param label the presentation name of the site to visit.
+ * @param siteURL the URL of the site to visit.
+ * @param categoriesToSkip an array of category names that should be skipped or <samp>null</samp> if all features should be considered.
+ */
+ public void addSearchSite(
+ String label,
+ URL siteURL,
+ String[] categoriesToSkip) {
+ sites.add(new UpdateSearchSite(label, siteURL, categoriesToSkip));
+ }
+
+ /**
+ * Returns the sites that should be visited during the search.
+ * @return an array of site adapters
+ */
+ public IUpdateSearchSite[] getSearchSites() {
+ return (UpdateSearchSite[]) sites.toArray(
+ new UpdateSearchSite[sites.size()]);
+ }
+
+ /**
+ * In addition to the sites added by addSearchSite(), features contribute their own update url's.
+ * This method returns true if those sites are also searched.
+ * @return true if update site provided by features are also searched. Default is true.
+ */
+ public boolean isFeatureProvidedSitesEnabled(){
+ return isFeatureProvidedSitesEnabled;
+ }
+
+ /**
+ * Enable or disable searching of feature provided update sites.
+ * If disabled, only sites added by addSearchSite() are searched.
+ * @param enable false to disable searching of feature provided sites. By default, these sites are searched.
+ */
+ public void setFeatureProvidedSitesEnabled(boolean enable){
+ this.isFeatureProvidedSitesEnabled = enable;
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/VersionedIdentifiersFilter.java b/update/org.eclipse.update.core/src/org/eclipse/update/search/VersionedIdentifiersFilter.java
new file mode 100644
index 0000000..996bd02
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/VersionedIdentifiersFilter.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.search;
+
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+
+
+/**
+ * This class can be added to the update search request
+ * to filter out features that are not part of the specified set.
+ *
+ * <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>
+ * @see UpdateSearchRequest
+ * @see IUpdateSearchFilter
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class VersionedIdentifiersFilter extends BaseFilter {
+ private ArrayList vids;
+
+ public VersionedIdentifiersFilter() {
+ this(new VersionedIdentifier[0]);
+ }
+
+ public VersionedIdentifiersFilter(VersionedIdentifier[] vids) {
+ this.vids = new ArrayList(vids.length);
+ for (int i=0; i<vids.length; i++)
+ this.vids.add(vids[i]);
+ }
+
+ public void add(VersionedIdentifier vid) {
+ vids.add(vid);
+ }
+
+ public boolean accept(IFeatureReference match) {
+ try {
+ for (int i=0; i<vids.size(); i++) {
+ VersionedIdentifier vid = (VersionedIdentifier)vids.get(i);
+ // installed version is the same as the match - accept
+ if (vid.equals(match.getVersionedIdentifier()))
+ return true;
+ }
+ return false;
+ } catch (CoreException e) {
+ return false;
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/search/package.html b/update/org.eclipse.update.core/src/org/eclipse/update/search/package.html
new file mode 100644
index 0000000..350db90
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/search/package.html
@@ -0,0 +1,18 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="Author" content="IBM">
+ <title>Package-level Javadoc</title>
+</head>
+<body>
+Provides support for performing searches and filtering of features.
+<h2>
+Package Specification</h2>
+This package contains interfaces and helper classes for creating and executing search operations.
+<p>
+<b>Note:</b> This package has been deprecated and will be deleted in a future
+release. See bug 311590 for details.
+</p>
+</body>
+</html>
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/standalone/AddSiteCommand.java b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/AddSiteCommand.java
new file mode 100644
index 0000000..8af4b11
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/AddSiteCommand.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.standalone;
+import java.io.*;
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.*;
+import org.eclipse.update.operations.*;
+
+/**
+ * Command to add a new product extension site.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class AddSiteCommand extends ScriptedCommand {
+ private ISite site;
+ private File sitePath;
+
+ /**
+ * @param fromSite if specified, list only the features from the specified local install site
+ */
+ public AddSiteCommand(String fromSite) throws Exception {
+ try {
+ if (fromSite != null) {
+ sitePath = new File(fromSite);
+ if (!sitePath.exists())
+ throw new Exception(Messages.Standalone_noSite + fromSite);
+
+ URL fromSiteURL = sitePath.toURL();
+ site = SiteManager.getSite(fromSiteURL, null);
+ if (site == null) {
+ throw new Exception(Messages.Standalone_noSite + fromSite);
+ }
+ IConfiguredSite csite = site.getCurrentConfiguredSite();
+ if (csite != null)
+ throw new Exception(Messages.Standalone_siteConfigured + fromSite);
+ } else {
+ throw new Exception(Messages.Standalone_noSite3 );
+ }
+ } catch (Exception e) {
+ throw e;
+ }
+ }
+
+ /**
+ */
+ public boolean run(IProgressMonitor monitor) {
+ // check if the config file has been modifed while we were running
+ IStatus status = OperationsManager.getValidator().validatePlatformConfigValid();
+ if (status != null) {
+ UpdateCore.log(status);
+ return false;
+ }
+
+ if (site == null)
+ return false;
+
+ try {
+ IConfiguredSite csite = getConfiguration().createConfiguredSite(sitePath);
+ getConfiguration().addConfiguredSite(csite);
+ // update the sites array to pick up new site
+ getConfiguration().getConfiguredSites();
+ SiteManager.getLocalSite().save();
+ return true;
+ } catch (CoreException e) {
+ UpdateCore.log(e);
+ return false;
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/standalone/CmdLineArgs.java b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/CmdLineArgs.java
new file mode 100644
index 0000000..7ca7891
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/CmdLineArgs.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.standalone;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.mirror.MirrorCommand;
+
+/**
+ * This class parses the command line arguments for update standalone commands
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class CmdLineArgs {
+ private HashMap options = new HashMap();
+ public CmdLineArgs(String[] args) {
+// // default command
+// options.put("-command", "install");
+
+ for (int i = 0; i < args.length - 1; i++) {
+ if ("-command".equals(args[i])) { //$NON-NLS-1$
+ if (isValidCommand(args[i + 1])) {
+ options.put("-command", args[i + 1]); //$NON-NLS-1$
+ i++;
+ } else {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(
+ Utilities.newCoreException(
+ Messages.Standalone_invalidCmd + args[i + 1],
+ null));
+ return;
+ }
+ }
+
+ if (isValidParam(args[i])) {
+ options.put(args[i], args[i + 1]);
+ i++;
+
+ }
+ // -to should specify a directory
+ // if -to specifies file URL, change it to a directory
+ String to = (String) options.get("-to"); //$NON-NLS-1$
+ if (to != null && to.startsWith("file:")) { //$NON-NLS-1$
+ try {
+ URL url = new URL(to);
+ options.put("-to", url.getFile()); //$NON-NLS-1$
+ } catch (MalformedURLException mue) {
+ }
+ }
+ }
+ }
+
+ private boolean isValidParam(String param) {
+ return param.equals("-command") //$NON-NLS-1$
+ || param.equals("-version") //$NON-NLS-1$
+ || param.equals("-to") //$NON-NLS-1$
+ || param.equals("-from") //$NON-NLS-1$
+ || param.equals("-featureId") //$NON-NLS-1$
+ || param.equals("-verifyOnly") //$NON-NLS-1$
+ || param.equals("-mirrorURL") //$NON-NLS-1$
+ || param.equals("-ignoreMissingPlugins"); //$NON-NLS-1$
+ }
+
+ private boolean isValidCommand(String cmd) {
+ if (cmd == null)
+ return false;
+ else
+ return cmd.equals("install") //$NON-NLS-1$
+ || cmd.equals("enable") //$NON-NLS-1$
+ || cmd.equals("disable") //$NON-NLS-1$
+ || cmd.equals("search") //$NON-NLS-1$
+ || cmd.equals("update") //$NON-NLS-1$
+ || cmd.equals("mirror") //$NON-NLS-1$
+ || cmd.equals("uninstall") //$NON-NLS-1$
+ || cmd.equals("listFeatures") //$NON-NLS-1$
+ || cmd.equals("addSite") //$NON-NLS-1$
+ || cmd.equals("removeSite"); //$NON-NLS-1$
+ }
+
+ public ScriptedCommand getCommand() {
+ try {
+ String cmd = (String) options.get("-command"); //$NON-NLS-1$
+ if (cmd == null)
+ return null;
+ if (cmd.equals("install")) //$NON-NLS-1$
+ return new InstallCommand(
+ (String) options.get("-featureId"), //$NON-NLS-1$
+ (String) options.get("-version"), //$NON-NLS-1$
+ (String) options.get("-from"), //$NON-NLS-1$
+ (String) options.get("-to"), //$NON-NLS-1$
+ (String) options.get("-verifyOnly")); //$NON-NLS-1$
+ else if (cmd.equals("enable")) //$NON-NLS-1$
+ return new EnableCommand(
+ (String) options.get("-featureId"), //$NON-NLS-1$
+ (String) options.get("-version"), //$NON-NLS-1$
+ (String) options.get("-to"), //$NON-NLS-1$
+ (String) options.get("-verifyOnly")); //$NON-NLS-1$
+ else if (cmd.equals("disable")) //$NON-NLS-1$
+ return new DisableCommand(
+ (String) options.get("-featureId"), //$NON-NLS-1$
+ (String) options.get("-version"), //$NON-NLS-1$
+ (String) options.get("-to"), //$NON-NLS-1$
+ (String) options.get("-verifyOnly")); //$NON-NLS-1$
+ else if (cmd.equals("search")) //$NON-NLS-1$
+ return new SearchCommand((String) options.get("-from")); //$NON-NLS-1$
+ else if (cmd.equals("update")) //$NON-NLS-1$
+ return new UpdateCommand(
+ (String) options.get("-featureId"), //$NON-NLS-1$
+ (String) options.get("-version"), //$NON-NLS-1$
+ (String) options.get("-verifyOnly")); //$NON-NLS-1$
+ else if (cmd.equals("mirror")) //$NON-NLS-1$
+ return new MirrorCommand(
+ (String) options.get("-featureId"), //$NON-NLS-1$
+ (String) options.get("-version"), //$NON-NLS-1$
+ (String) options.get("-from"), //$NON-NLS-1$
+ (String) options.get("-to"), //$NON-NLS-1$
+ (String) options.get("-mirrorURL"), //$NON-NLS-1$
+ (String) options.get("-ignoreMissingPlugins")); //$NON-NLS-1$
+ else if (cmd.equals("uninstall")) //$NON-NLS-1$
+ return new UninstallCommand(
+ (String) options.get("-featureId"), //$NON-NLS-1$
+ (String) options.get("-version"), //$NON-NLS-1$
+ (String) options.get("-to"), //$NON-NLS-1$
+ (String) options.get("-verifyOnly")); //$NON-NLS-1$
+ else if (cmd.equals("listFeatures")) //$NON-NLS-1$
+ return new ListFeaturesCommand((String) options.get("-from")); //$NON-NLS-1$
+ else if (cmd.equals("addSite")) //$NON-NLS-1$
+ return new AddSiteCommand((String) options.get("-from")); //$NON-NLS-1$
+ else if (cmd.equals("removeSite")) //$NON-NLS-1$
+ return new RemoveSiteCommand((String) options.get("-to")); //$NON-NLS-1$
+ else
+ return null;
+ } catch (Exception e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ return null;
+ }
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/standalone/DisableCommand.java b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/DisableCommand.java
new file mode 100644
index 0000000..856ad73
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/DisableCommand.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.standalone;
+import java.io.*;
+import java.lang.reflect.*;
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.*;
+import org.eclipse.update.internal.operations.*;
+import org.eclipse.update.operations.*;
+
+/**
+ * Command to disable (unconfigure) a feature
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class DisableCommand extends ScriptedCommand {
+
+ private IConfiguredSite targetSite;
+ private IFeature feature;
+
+ public DisableCommand(
+ String featureId,
+ String version,
+ String toSite,
+ String verifyOnly)
+ throws Exception {
+
+ super(verifyOnly);
+
+ try {
+ IConfiguredSite[] sites = getConfiguration().getConfiguredSites();
+
+ // Get site containing the feature to disable
+ if (toSite != null) {
+ URL toSiteURL = new File(toSite).toURL();
+ if (SiteManager.getSite(toSiteURL, null) == null) {
+ throw new Exception(Messages.Standalone_noSite + toSite);
+ }
+ targetSite =
+ SiteManager
+ .getSite(toSiteURL, null)
+ .getCurrentConfiguredSite();
+ }
+ if (targetSite == null) {
+ for (int i = 0; i < sites.length; i++) {
+ if (sites[i].isProductSite()) {
+ targetSite = sites[i];
+ break;
+ }
+ }
+ }
+
+ IFeature[] features =
+ UpdateUtils.searchSite(featureId, targetSite, true);
+ if (features == null || features.length == 0) {
+ throw new Exception(NLS.bind(Messages.Standalone_noFeatures3, (new String[] { featureId })));
+ }
+ if (version == null || version.trim().length() == 0)
+ feature = features[0]; // pick the first feature
+ else
+ for (int i = 0; features != null && i < features.length; i++) {
+ if (features[i]
+ .getVersionedIdentifier()
+ .getVersion()
+ .toString()
+ .equals(version)) {
+ feature = features[i];
+ break;
+ }
+ }
+ if (feature == null) {
+ throw new Exception(NLS.bind(Messages.Standalone_noFeatures4, (new String[] { featureId, version })));
+ }
+
+ } catch (MalformedURLException e) {
+ throw e;
+ } catch (CoreException e) {
+ throw e;
+ }
+ }
+
+ /**
+ */
+ public boolean run(IProgressMonitor monitor) {
+ // check if the config file has been modifed while we were running
+ IStatus status = OperationsManager.getValidator().validatePlatformConfigValid();
+ if (status != null) {
+ UpdateCore.log(status);
+ return false;
+ }
+ if (isVerifyOnly()) {
+ status =
+ OperationsManager.getValidator().validatePendingUnconfig(
+ feature);
+ if (status != null && status.getCode() == IStatus.WARNING)
+ UpdateCore.log(status);
+ return status == null || status.getCode() == IStatus.WARNING;
+ }
+
+ final IUnconfigFeatureOperation configOperation =
+ OperationsManager.getOperationFactory().createUnconfigOperation(
+ targetSite,
+ feature);
+
+ try {
+ configOperation.execute(monitor, this);
+ return true;
+ } catch (CoreException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ return false;
+ } catch (InvocationTargetException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ return false;
+ }
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/standalone/EnableCommand.java b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/EnableCommand.java
new file mode 100644
index 0000000..7fdf105
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/EnableCommand.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.standalone;
+import java.io.*;
+import java.lang.reflect.*;
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.*;
+import org.eclipse.update.internal.operations.*;
+import org.eclipse.update.operations.*;
+
+/**
+ * Command to enable (configure) a feature.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class EnableCommand extends ScriptedCommand {
+
+ private IConfiguredSite targetSite;
+ private IFeature feature;
+
+ public EnableCommand(
+ String featureId,
+ String version,
+ String toSite,
+ String verifyOnly)
+ throws Exception {
+
+ super(verifyOnly);
+
+ try {
+ IConfiguredSite[] sites = getConfiguration().getConfiguredSites();
+
+ // Get site to enable to
+ if (toSite != null) {
+ URL toSiteURL = new File(toSite).toURL();
+ if (SiteManager.getSite(toSiteURL, null) == null) {
+ throw new Exception(Messages.Standalone_noSite + toSite);
+ }
+ targetSite =
+ SiteManager
+ .getSite(toSiteURL, null)
+ .getCurrentConfiguredSite();
+ }
+ if (targetSite == null) {
+ for (int i = 0; i < sites.length; i++) {
+ if (sites[i].isProductSite()) {
+ targetSite = sites[i];
+ break;
+ }
+ }
+ }
+
+ IFeature[] features =
+ UpdateUtils.searchSite(featureId, targetSite, false);
+ if (features == null || features.length == 0) {
+ throw new Exception(NLS.bind(Messages.Standalone_noFeatures1, (new String[] { featureId })));
+ }
+ if (version == null || version.trim().length() == 0)
+ feature = features[0]; // pick the first feature
+ else
+ for (int i = 0; features != null && i < features.length; i++) {
+ if (features[i]
+ .getVersionedIdentifier()
+ .getVersion()
+ .toString()
+ .equals(version)
+ && !targetSite.isConfigured(features[i])) {
+ feature = features[i];
+ break;
+ }
+ }
+ if (feature == null) {
+ throw new Exception(NLS.bind(Messages.Standalone_noFeatures2, (new String[] { featureId, version })));
+ }
+
+ } catch (MalformedURLException e) {
+ throw e;
+ } catch (CoreException e) {
+ throw e;
+ }
+ }
+
+ /**
+ */
+ public boolean run(IProgressMonitor monitor) {
+ // check if the config file has been modifed while we were running
+ IStatus status = OperationsManager.getValidator().validatePlatformConfigValid();
+ if (status != null) {
+ UpdateCore.log(status);
+ return false;
+ }
+
+ if (isVerifyOnly()) {
+ status =
+ OperationsManager.getValidator().validatePendingConfig(feature);
+ if (status != null && status.getCode() == IStatus.WARNING)
+ UpdateCore.log(status);
+ return status == null || status.getCode() == IStatus.WARNING;
+ }
+
+ final IConfigFeatureOperation configOperation =
+ OperationsManager.getOperationFactory().createConfigOperation(
+ targetSite,
+ feature);
+
+ try {
+ configOperation.execute(monitor, this);
+ return true;
+ } catch (CoreException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ return false;
+ } catch (InvocationTargetException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ return false;
+ }
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/standalone/InstallCommand.java b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/InstallCommand.java
new file mode 100644
index 0000000..4dbc525
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/InstallCommand.java
@@ -0,0 +1,270 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.standalone;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.IConfiguredSite;
+import org.eclipse.update.core.IFeature;
+import org.eclipse.update.core.ISite;
+import org.eclipse.update.core.SiteManager;
+import org.eclipse.update.core.Utilities;
+import org.eclipse.update.core.VersionedIdentifier;
+import org.eclipse.update.internal.configurator.UpdateURLDecoder;
+import org.eclipse.update.internal.core.Messages;
+import org.eclipse.update.internal.core.UpdateCore;
+import org.eclipse.update.internal.core.UpdateManagerUtils;
+import org.eclipse.update.internal.operations.DuplicateConflictsValidator;
+import org.eclipse.update.internal.operations.UpdateUtils;
+import org.eclipse.update.internal.search.SiteSearchCategory;
+import org.eclipse.update.operations.IBatchOperation;
+import org.eclipse.update.operations.IInstallFeatureOperation;
+import org.eclipse.update.operations.OperationsManager;
+import org.eclipse.update.search.BackLevelFilter;
+import org.eclipse.update.search.EnvironmentFilter;
+import org.eclipse.update.search.IUpdateSearchResultCollector;
+import org.eclipse.update.search.UpdateSearchRequest;
+import org.eclipse.update.search.UpdateSearchScope;
+import org.eclipse.update.search.VersionedIdentifiersFilter;
+
+/**
+ * Command to install a feature.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class InstallCommand extends ScriptedCommand {
+
+ private IConfiguredSite targetSite;
+ private UpdateSearchRequest searchRequest;
+ private UpdateSearchResultCollector collector;
+ private URL remoteSiteURL;
+ private String featureId;
+ private String version;
+
+ public InstallCommand(
+ String featureId,
+ String version,
+ String fromSite,
+ String toSite,
+ String verifyOnly)
+ throws Exception {
+
+ super(verifyOnly);
+
+ try {
+ this.featureId = featureId;
+ this.version = version;
+
+ //PAL foundation
+ this.remoteSiteURL = new URL(UpdateURLDecoder.decode(fromSite, "UTF-8")); //$NON-NLS-1$
+
+ // Get site to install to
+ targetSite = getTargetSite(toSite);
+ // if no site, try selecting the site that already has the old feature
+ if (targetSite == null)
+ targetSite = UpdateUtils.getSiteWithFeature(getConfiguration(), featureId);
+ // if still no site, pick the product site, if writeable
+ if (targetSite == null) {
+ IConfiguredSite[] sites = getConfiguration().getConfiguredSites();
+ for (int i = 0; i < sites.length; i++) {
+ if (sites[i].isProductSite() && sites[i].isUpdatable()) {
+ targetSite = sites[i];
+ break;
+ }
+ }
+ }
+ // if all else fails, pick the first updateable site
+ if (targetSite == null) {
+ IConfiguredSite[] sites = getConfiguration().getConfiguredSites();
+ for (int i = 0; i < sites.length; i++) {
+ if (sites[i].isUpdatable()) {
+ targetSite = sites[i];
+ break;
+ }
+ }
+ }
+ // are we still checking for sites? forget about it
+ if (targetSite == null)
+ throw Utilities.newCoreException(
+ Messages.Standalone_cannotInstall + featureId + " " + version, //$NON-NLS-1$
+ null);
+
+ UpdateSearchScope searchScope = new UpdateSearchScope();
+ searchScope.addSearchSite(
+ NLS.bind( Messages.InstallCommand_site, remoteSiteURL.toExternalForm()),
+ remoteSiteURL,
+ new String[0]);
+
+ searchRequest =
+ new UpdateSearchRequest(new SiteSearchCategory(), searchScope);
+ VersionedIdentifier vid =
+ new VersionedIdentifier(featureId, version);
+ searchRequest.addFilter(
+ new VersionedIdentifiersFilter(
+ new VersionedIdentifier[] { vid }));
+ searchRequest.addFilter(new EnvironmentFilter());
+ searchRequest.addFilter(new BackLevelFilter());
+
+ collector = new UpdateSearchResultCollector();
+
+ } catch (MalformedURLException e) {
+ throw e;
+ } catch (CoreException e) {
+ throw e;
+ }
+ }
+
+ /**
+ */
+ public boolean run(IProgressMonitor monitor) {
+ try {
+ monitor.beginTask(Messages.Standalone_installing, 4);
+ searchRequest.performSearch(collector, new SubProgressMonitor(monitor,1));
+ IInstallFeatureOperation[] operations = collector.getOperations();
+ if (operations == null || operations.length == 0) {
+ throw Utilities.newCoreException(
+ NLS.bind(Messages.Standalone_notFoundOrNewer, featureId + ' ' + version, remoteSiteURL),
+ null);
+ }
+
+ // Check for duplication conflicts
+ ArrayList conflicts =
+ DuplicateConflictsValidator.computeDuplicateConflicts(
+ operations,
+ getConfiguration());
+ if (conflicts != null) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(Utilities.newCoreException(Messages.Standalone_duplicate, null));
+ System.out.println(Messages.Standalone_duplicate);
+ }
+
+ if (isVerifyOnly()) {
+ if (operations == null || operations.length == 0)
+ return false;
+ IStatus status = OperationsManager.getValidator().validatePendingChanges(operations);
+ if (status != null && status.getCode() == IStatus.ERROR)
+ throw new CoreException(status);
+ else
+ return true;
+ }
+
+ IBatchOperation installOperation =
+ OperationsManager
+ .getOperationFactory()
+ .createBatchInstallOperation(
+ operations);
+ try {
+ installOperation.execute(new SubProgressMonitor(monitor,3), this);
+ System.out.println(NLS.bind(Messages.Standalone_installed, featureId + ' ' + version));
+ return true;
+ } catch (Exception e) {
+ throw Utilities.newCoreException(
+ Messages.Standalone_cannotInstall + featureId + " " + version, //$NON-NLS-1$
+ e);
+ }
+ } catch (CoreException ce) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(ce);
+ return false;
+ } catch (OperationCanceledException ce) {
+ return true;
+ } finally {
+ monitor.done();
+ }
+ }
+
+ private IConfiguredSite getTargetSite(String toSite) throws Exception {
+ if (toSite == null)
+ return null;
+
+ IConfiguredSite[] configuredSites = getConfiguration().getConfiguredSites();
+ File sitePath = new File(toSite);
+ File secondaryPath = sitePath.getName().equals("eclipse") ? //$NON-NLS-1$
+ null : new File(sitePath, "eclipse"); //$NON-NLS-1$
+
+ for (int i = 0; i < configuredSites.length; i++) {
+ IConfiguredSite csite = configuredSites[i];
+ if (UpdateManagerUtils.sameURL(csite.getSite().getURL(),sitePath.toURL()))
+ return csite;
+ else if (secondaryPath != null && UpdateManagerUtils.sameURL(csite.getSite().getURL(),secondaryPath.toURL()))
+ return csite;
+ }
+
+ // extension site not found, need to create one
+ if (!sitePath.exists())
+ sitePath.mkdirs();
+ URL toSiteURL = sitePath.toURL();
+ ISite site = SiteManager.getSite(toSiteURL, null);
+ if (site == null) {
+ throw new Exception(Messages.Standalone_noSite + toSite);
+ }
+ IConfiguredSite csite = site.getCurrentConfiguredSite();
+ if (csite == null) {
+ csite = getConfiguration().createConfiguredSite(sitePath);
+ IStatus status = csite.verifyUpdatableStatus();
+ if (status.isOK())
+ getConfiguration().addConfiguredSite(csite);
+ else
+ throw new CoreException(status);
+
+ return csite;
+ }
+ return csite;
+ }
+ class UpdateSearchResultCollector implements IUpdateSearchResultCollector {
+ private ArrayList operations = new ArrayList();
+
+ public void accept(IFeature feature) {
+ if (feature
+ .getVersionedIdentifier()
+ .getIdentifier()
+ .equals(featureId)
+ && feature
+ .getVersionedIdentifier()
+ .getVersion()
+ .toString()
+ .equals(
+ version)) {
+ operations.add(
+ OperationsManager
+ .getOperationFactory()
+ .createInstallOperation(
+ targetSite,
+ feature,
+ null,
+ null,
+ null));
+ }
+ }
+ public IInstallFeatureOperation[] getOperations() {
+ IInstallFeatureOperation[] opsArray =
+ new IInstallFeatureOperation[operations.size()];
+ operations.toArray(opsArray);
+ return opsArray;
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/standalone/ListFeaturesCommand.java b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/ListFeaturesCommand.java
new file mode 100644
index 0000000..8ac038b
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/ListFeaturesCommand.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.standalone;
+import java.io.*;
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.*;
+
+
+/**
+ * Command to list all installed features.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class ListFeaturesCommand extends ScriptedCommand {
+ private IConfiguredSite[] sites = getConfiguration().getConfiguredSites();
+
+ /**
+ * @param fromSite if specified, list only the features from the specified local install site
+ */
+ public ListFeaturesCommand(String fromSite) throws Exception {
+ try {
+ if (fromSite != null) {
+ File sitePath = new File(fromSite);
+ if (!sitePath.exists())
+ throw new Exception(Messages.Standalone_noSite + fromSite);
+
+ URL fromSiteURL = sitePath.toURL();
+ ISite site = SiteManager.getSite(fromSiteURL, null);
+ if (site == null) {
+ throw new Exception(Messages.Standalone_noSite + fromSite);
+ }
+ IConfiguredSite csite = site.getCurrentConfiguredSite();
+ if (csite == null)
+ throw new Exception(Messages.Standalone_noConfiguredSite + fromSite);
+ sites = new IConfiguredSite[] { csite };
+ }
+
+ } catch (Exception e) {
+ throw e;
+ }
+ }
+
+ /**
+ */
+ public boolean run(IProgressMonitor monitor) {
+ try {
+ if (sites != null) {
+ for (int i = 0; i < sites.length; i++) {
+ System.out.println("Site: " + sites[i].getSite().getURL()); //$NON-NLS-1$
+ IFeatureReference[] features = sites[i]
+ .getFeatureReferences();
+ for (int f = 0; f < features.length; f++) {
+ boolean configured = sites[i].isConfigured(features[f]
+ .getFeature(null));
+ System.out.println(" Feature: " //$NON-NLS-1$
+ + features[f].getVersionedIdentifier()
+ .getIdentifier()
+ + " " //$NON-NLS-1$
+ + features[f].getVersionedIdentifier()
+ .getVersion() + " " //$NON-NLS-1$
+ + (configured ? "enabled" : "disabled")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ }
+ return true;
+ } catch (CoreException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ return false;
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/standalone/RemoveSiteCommand.java b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/RemoveSiteCommand.java
new file mode 100644
index 0000000..bbfece4
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/RemoveSiteCommand.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.standalone;
+import java.io.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.*;
+import org.eclipse.update.operations.*;
+
+
+/**
+ * Command to remove a product extension site.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class RemoveSiteCommand extends ScriptedCommand {
+ private IConfiguredSite csite;
+ private File sitePath;
+
+ /**
+ * @param toSite if specified, list only the features from the specified local install site
+ */
+ public RemoveSiteCommand(String toSite) throws Exception {
+ try {
+ if (toSite != null) {
+ sitePath = new File(toSite);
+ if (!sitePath.getName().equals("eclipse")) //$NON-NLS-1$
+ sitePath = new File(sitePath, "eclipse"); //$NON-NLS-1$
+ if (!sitePath.exists())
+ throw new Exception(Messages.Standalone_noSite + toSite);
+
+ IConfiguredSite[] csites = SiteManager.getLocalSite().getCurrentConfiguration().getConfiguredSites();
+ for (int i=0; i<csites.length; i++) {
+ File f = new File(csites[i].getSite().getURL().getFile());
+ if (f.equals(sitePath)) {
+ csite = csites[i];
+ break;
+ }
+ }
+
+ if (csite == null)
+ throw new Exception(Messages.Standalone_noConfiguredSite + toSite);
+ } else {
+ throw new Exception(Messages.Standalone_noSite3);
+ }
+
+ } catch (Exception e) {
+ throw e;
+ }
+ }
+
+ /**
+ */
+ public boolean run(IProgressMonitor monitor) {
+ // check if the config file has been modifed while we were running
+ IStatus status = OperationsManager.getValidator().validatePlatformConfigValid();
+ if (status != null) {
+ UpdateCore.log(status);
+ return false;
+ }
+ try {
+ getConfiguration().removeConfiguredSite(csite);
+ // update the sites array
+ getConfiguration().getConfiguredSites();
+ SiteManager.getLocalSite().save();
+ return true;
+ } catch (CoreException e) {
+ UpdateCore.log(e);
+ return false;
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/standalone/ScriptedCommand.java b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/ScriptedCommand.java
new file mode 100644
index 0000000..eead53b
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/ScriptedCommand.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.standalone;
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.*;
+import org.eclipse.update.operations.*;
+
+/**
+ * Parent class for all the update manager standalone commands.
+ * Subclasses will provide specific operations and the implementation of the run() method.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public abstract class ScriptedCommand implements IOperationListener {
+
+ private IInstallConfiguration config;
+ protected boolean verifyOnly;
+
+ /**
+ * Constructor
+ *
+ */
+ public ScriptedCommand() {
+ this(null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param verifyOnly if true, the command is not executed, but will only attempt to run the command.
+ * This is mostly used when wanted to know if the command would fail.
+ */
+ public ScriptedCommand(String verifyOnly) {
+ this.verifyOnly = "true".equals(verifyOnly); //$NON-NLS-1$
+ }
+
+ /**
+ * @return true if the command should only be run in simulation mode,
+ * to verify if it can execute.
+ */
+ protected final boolean isVerifyOnly() {
+ return verifyOnly;
+ }
+
+ /**
+ * Convenience method that executes the command with a null progress monitor.
+ */
+ public final boolean run() {
+ return run(new NullProgressMonitor());
+ }
+
+ /**
+ * Executes the command. Subclasses are responsible for implementing this method.
+ * If the command was constructed with verifyOnly=true, the command should not execute, but only verify it can execute.
+ * @param monitor progress monitor during command execution.
+ */
+ public abstract boolean run(IProgressMonitor monitor);
+
+ /**
+ * Applies the changes made to the current configuration.
+ */
+ public void applyChangesNow() {
+ OperationsManager.applyChangesNow();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.operations.IOperationListener#afterExecute(org.eclipse.update.operations.IOperation)
+ */
+ public boolean afterExecute(IOperation operation, Object data) {
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.update.operations.IOperationListener#beforeExecute(org.eclipse.update.operations.IOperation)
+ */
+ public boolean beforeExecute(IOperation operation, Object data) {
+ return true;
+ }
+
+ /**
+ * @return the installation configuration affected by the command
+ */
+ public final IInstallConfiguration getConfiguration() {
+ try {
+ ILocalSite localSite = SiteManager.getLocalSite();
+ config = localSite.getCurrentConfiguration();
+ } catch (CoreException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ }
+ return config;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/standalone/SearchCommand.java b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/SearchCommand.java
new file mode 100644
index 0000000..a6c989d
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/SearchCommand.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.standalone;
+import java.io.*;
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.configurator.UpdateURLDecoder;
+import org.eclipse.update.internal.core.*;
+import org.eclipse.update.internal.search.*;
+import org.eclipse.update.search.*;
+
+/**
+ * Command to search an update site and list its features.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class SearchCommand extends ScriptedCommand {
+
+ private URL remoteSiteURL;
+ private UpdateSearchRequest searchRequest;
+ private IUpdateSearchResultCollector collector;
+
+ public SearchCommand(String fromSite) {
+ try {
+ //PAL foundation
+ this.remoteSiteURL = new URL(UpdateURLDecoder.decode(fromSite, "UTF-8")); //$NON-NLS-1$
+ UpdateSearchScope searchScope = new UpdateSearchScope();
+ searchScope.addSearchSite(
+ "remoteSite", //$NON-NLS-1$
+ remoteSiteURL,
+ new String[0]);
+ searchRequest =
+ new UpdateSearchRequest(new SiteSearchCategory(), searchScope);
+ collector = new UpdateSearchResultCollector();
+ } catch (MalformedURLException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ } catch (UnsupportedEncodingException e) {
+ }
+ }
+
+ /**
+ */
+ public boolean run(IProgressMonitor monitor) {
+ try {
+ monitor.beginTask(Messages.Standalone_searching + remoteSiteURL.toExternalForm(), 4);
+ searchRequest.performSearch(collector, monitor);
+ return true;
+ } catch (CoreException ce) {
+ IStatus status = ce.getStatus();
+ if (status != null
+ && status.getCode() == ISite.SITE_ACCESS_EXCEPTION) {
+ // Just show this but do not throw exception
+ // because there may be results anyway.
+ System.out.println(Messages.Standalone_connection);
+ } else {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(ce);
+ }
+ return false;
+ } catch (OperationCanceledException ce) {
+ return true;
+ } finally {
+ monitor.done();
+ }
+ }
+
+
+ class UpdateSearchResultCollector implements IUpdateSearchResultCollector {
+ public void accept(IFeature feature) {
+ System.out.println(
+ "\"" //$NON-NLS-1$
+ + feature.getLabel()
+ + "\" " //$NON-NLS-1$
+ + feature.getVersionedIdentifier().getIdentifier()
+ + " " //$NON-NLS-1$
+ + feature.getVersionedIdentifier().getVersion());
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/standalone/StandaloneUpdateApplication.java b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/StandaloneUpdateApplication.java
new file mode 100644
index 0000000..f27932f
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/StandaloneUpdateApplication.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.standalone;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.internal.core.*;
+
+/**
+ * The application class used to launch standalone update commands.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class StandaloneUpdateApplication implements IPlatformRunnable {
+
+ public final static Integer EXIT_ERROR = new Integer(1);
+ private static boolean loggedException = false;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.boot.IPlatformRunnable#run(java.lang.Object)
+ */
+ public Object run(Object args) throws Exception {
+ if (args == null)
+ return EXIT_ERROR;
+ if (args instanceof String[]) {
+ String[] params = (String[]) args;
+ CmdLineArgs cmdLineArgs = new CmdLineArgs(params);
+ ScriptedCommand cmd = cmdLineArgs.getCommand();
+ if (cmd == null) {
+ System.out.println(NLS.bind(Messages.Standalone_cmdFailed, (new String[] { Platform.getLogFileLocation().toOSString() })));
+ return EXIT_ERROR;
+ }
+ loggedException = false;
+ boolean result = cmd.run();
+ if (result) {
+ if (loggedException) {
+ System.out.println(NLS.bind(Messages.Standalone_cmdCompleteWithErrors, (new String[] { Platform.getLogFileLocation().toOSString() })));
+ } else {
+ System.out.println(Messages.Standalone_cmdOK);
+ }
+ return IPlatformRunnable.EXIT_OK;
+ } else {
+ if (loggedException) {
+ System.out.println(NLS.bind(Messages.Standalone_cmdFailed, (new String[] { Platform.getLogFileLocation().toOSString() })));
+ } else {
+ System.out.println(Messages.Standalone_cmdFailedNoLog);
+ }
+ return EXIT_ERROR;
+ }
+ }
+ return EXIT_ERROR;
+ }
+ public static void exceptionLogged() {
+ loggedException = true;
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/standalone/UninstallCommand.java b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/UninstallCommand.java
new file mode 100644
index 0000000..b360535
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/UninstallCommand.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.standalone;
+import java.io.*;
+import java.lang.reflect.*;
+import java.net.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.*;
+import org.eclipse.update.internal.operations.*;
+import org.eclipse.update.operations.*;
+
+/**
+ * Command to uninstall a feature. The feature must be disabled before uninstalling it.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class UninstallCommand extends ScriptedCommand {
+
+ private IConfiguredSite targetSite;
+ private IFeature feature;
+
+ public UninstallCommand(
+ String featureId,
+ String version,
+ String toSite,
+ String verifyOnly)
+ throws Exception {
+
+ super(verifyOnly);
+
+ try {
+ IConfiguredSite[] sites = getConfiguration().getConfiguredSites();
+
+ // Get site that contains the feature to uninstall
+ if (toSite != null) {
+ URL toSiteURL = new File(toSite).toURL();
+ if (SiteManager.getSite(toSiteURL, null) == null) {
+ throw new Exception(Messages.Standalone_noSite + toSite);
+ }
+ targetSite =
+ SiteManager
+ .getSite(toSiteURL, null)
+ .getCurrentConfiguredSite();
+ }
+ if (targetSite == null) {
+ for (int i = 0; i < sites.length; i++) {
+ if (sites[i].isProductSite()) {
+ targetSite = sites[i];
+ break;
+ }
+ }
+ }
+
+ IFeature[] features =
+ UpdateUtils.searchSite(featureId, targetSite, false);
+ if (features == null || features.length == 0) {
+ throw new Exception(NLS.bind(Messages.Standalone_noFeatures1, (new String[] { featureId })));
+ }
+ if (version == null || version.trim().length() == 0)
+ feature = features[0]; // pick the first feature
+ else
+ for (int i = 0; features != null && i < features.length; i++) {
+ if (features[i]
+ .getVersionedIdentifier()
+ .getVersion()
+ .toString()
+ .equals(version)
+ && !targetSite.isConfigured(features[i])) {
+ feature = features[i];
+ break;
+ }
+ }
+ if (feature == null) {
+ throw new Exception(NLS.bind(Messages.Standalone_noFeatures2, (new String[] { featureId, version })));
+ }
+
+ } catch (MalformedURLException e) {
+ throw e;
+ } catch (CoreException e) {
+ throw e;
+ }
+ }
+
+ /**
+ */
+ public boolean run(IProgressMonitor monitor) {
+ // check if the config file has been modifed while we were running
+ IStatus status = OperationsManager.getValidator().validatePlatformConfigValid();
+ if (status != null) {
+ UpdateCore.log(status);
+ return false;
+ }
+ if (InstallRegistry.getInstance().get("feature_"+ feature.getVersionedIdentifier()) == null) { //$NON-NLS-1$
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(Utilities.newCoreException(NLS.bind(Messages.UninstallCommand_featureNotInstalledByUM, (new String[] { feature.toString() })),null));
+ return false;
+ }
+
+ if (isVerifyOnly()) {
+ // if reached this point, it is safe to uninstall
+ return true;
+ }
+
+ final IUninstallFeatureOperation uninstallOperation =
+ OperationsManager.getOperationFactory().createUninstallOperation(
+ targetSite,
+ feature);
+
+ try {
+ uninstallOperation.execute(monitor, this);
+ return true;
+ } catch (CoreException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ return false;
+ } catch (InvocationTargetException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ return false;
+ }
+ }
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/standalone/UpdateCommand.java b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/UpdateCommand.java
new file mode 100644
index 0000000..8312c5e
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/UpdateCommand.java
@@ -0,0 +1,225 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.update.standalone;
+
+import java.net.*;
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.update.configuration.*;
+import org.eclipse.update.core.*;
+import org.eclipse.update.internal.core.*;
+import org.eclipse.update.internal.operations.*;
+import org.eclipse.update.operations.*;
+import org.eclipse.update.search.*;
+
+/**
+ * Command to update and existing feature.
+ * <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>
+ * @since 3.0
+ * @deprecated The org.eclipse.update component has been replaced by Equinox p2.
+ * This API will be deleted in a future release. See bug 311590 for details.
+ */
+public class UpdateCommand extends ScriptedCommand {
+
+ private IConfiguredSite targetSite;
+ private UpdateSearchRequest searchRequest;
+ private UpdateSearchResultCollector collector;
+ private String featureId;
+ //private String version;
+ private IFeature currentFeature;
+
+ /**
+ * Update command for updating a feature to a newer version.
+ * @param featureId
+ * @param verifyOnly
+ * @throws Exception
+ */
+ public UpdateCommand(String featureId, String verifyOnly)
+ throws Exception {
+ this(featureId, null, verifyOnly);
+ }
+
+ /**
+ * Update command for updating a feature to a specified newer version.
+ * @param featureId
+ * @param version
+ * @param verifyOnly
+ * @throws Exception
+ */
+ public UpdateCommand(String featureId, String version, String verifyOnly)
+ throws Exception {
+
+ super(verifyOnly);
+
+ try {
+ this.featureId = featureId;
+ //this.version = version;
+ if (featureId != null) {
+ this.targetSite =
+ UpdateUtils.getSiteWithFeature(
+ getConfiguration(),
+ featureId);
+ if (targetSite == null) {
+ throw new Exception(NLS.bind(Messages.Standalone_noConfigSiteForFeature, (new String[] { featureId })));
+ }
+ IFeature[] currentFeatures =
+ UpdateUtils.searchSite(featureId, targetSite, true);
+ if (currentFeatures == null || currentFeatures.length == 0) {
+ throw new Exception(NLS.bind(Messages.Standalone_noFeatures3, (new String[] { featureId })));
+ }
+ this.currentFeature = currentFeatures[0];
+ } else {
+ // Get site to install to
+ IConfiguredSite[] sites =
+ getConfiguration().getConfiguredSites();
+ for (int i = 0; i < sites.length; i++) {
+ if (sites[i].isProductSite()) {
+ targetSite = sites[i];
+ break;
+ }
+ }
+ }
+ if (currentFeature == null)
+ searchRequest = UpdateUtils.createNewUpdatesRequest(null);
+ else {
+ searchRequest =
+ UpdateUtils.createNewUpdatesRequest(
+ new IFeature[] { currentFeature });
+ if (version != null)
+ searchRequest.addFilter(
+ new VersionedIdentifiersFilter(
+ new VersionedIdentifier[] { new VersionedIdentifier(featureId, version) }));
+ }
+
+ collector = new UpdateSearchResultCollector();
+
+ } catch (MalformedURLException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ } catch (CoreException e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(e);
+ }
+ }
+
+ /**
+ */
+ public boolean run(IProgressMonitor monitor) {
+ // check if the config file has been modifed while we were running
+ IStatus status = OperationsManager.getValidator().validatePlatformConfigValid();
+ if (status != null) {
+ UpdateCore.log(status);
+ return false;
+ }
+ try {
+ monitor.beginTask(Messages.Standalone_updating, 4);
+ searchRequest.performSearch(collector, new SubProgressMonitor(monitor,1));
+ IInstallFeatureOperation[] operations = collector.getOperations();
+ if (operations == null || operations.length == 0) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(Utilities.newCoreException(NLS.bind(Messages.Standalone_noUpdate, (new String[] { featureId })), null));
+ return false;
+ }
+
+ // Check for duplication conflicts
+ ArrayList conflicts =
+ DuplicateConflictsValidator.computeDuplicateConflicts(
+ operations,
+ getConfiguration());
+ if (conflicts != null) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(Utilities.newCoreException(Messages.Standalone_duplicate, null));
+ System.out.println(Messages.Standalone_duplicate);
+ }
+
+ if (isVerifyOnly()) {
+ status = OperationsManager.getValidator().validatePendingChanges(operations);
+ if (status != null && status.getCode() == IStatus.ERROR)
+ throw new CoreException(status);
+ else
+ return true;
+ }
+
+ IBatchOperation installOperation =
+ OperationsManager
+ .getOperationFactory()
+ .createBatchInstallOperation(
+ operations);
+ try {
+ installOperation.execute(new SubProgressMonitor(monitor,3), this);
+ System.out.println(NLS.bind(Messages.Standalone_updated, featureId));
+ return true;
+ } catch (Exception e) {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(
+ Utilities.newCoreException(
+ NLS.bind(Messages.Standalone_noUpdate, (new String[] { featureId })),
+ e));
+ return false;
+ }
+ } catch (CoreException ce) {
+ status = ce.getStatus();
+ if (status != null
+ && status.getCode() == ISite.SITE_ACCESS_EXCEPTION) {
+ // Just show this but do not throw exception
+ // because there may be results anyway.
+ System.out.println(Messages.Standalone_connection);
+ } else {
+ StandaloneUpdateApplication.exceptionLogged();
+ UpdateCore.log(ce);
+ }
+ return false;
+ } catch (OperationCanceledException ce) {
+ return true;
+ } finally {
+ monitor.done();
+ }
+ }
+
+
+ class UpdateSearchResultCollector implements IUpdateSearchResultCollector {
+ private ArrayList operations = new ArrayList();
+
+ public void accept(IFeature feature) {
+
+ IInstallFeatureOperation op =
+ OperationsManager.getOperationFactory().createInstallOperation(
+ null,
+ feature,
+ null,
+ null,
+ null);
+
+ IConfiguredSite site =
+ UpdateUtils.getDefaultTargetSite(getConfiguration(), op);
+ if (site == null)
+ site = UpdateUtils.getAffinitySite(getConfiguration(), feature);
+ if (site == null)
+ site = targetSite;
+
+ op.setTargetSite(site);
+ operations.add(op);
+ }
+ public IInstallFeatureOperation[] getOperations() {
+ IInstallFeatureOperation[] opsArray =
+ new IInstallFeatureOperation[operations.size()];
+ operations.toArray(opsArray);
+ return opsArray;
+ }
+ }
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/standalone/package.html b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/package.html
new file mode 100644
index 0000000..7044920
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/standalone/package.html
@@ -0,0 +1,21 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="Author" content="IBM">
+ <meta name="GENERATOR" content="Mozilla/4.72 [en] (Windows NT 5.0; U) [Netscape]">
+ <title>Package-level Javadoc</title>
+</head>
+<body>
+Provides support for performing various install/update operations from the command line.
+<h2>
+Package Specification</h2>
+This package contains interfaces for performing update/install operations
+without using the Update Manager user interface. In general, it is best to use these
+classes for command line invocation, but it is possible to also use them programmatically.
+<p>
+<b>Note:</b> This package has been deprecated and will be deleted in a future
+release. See bug 311590 for details.
+</p>
+</body>
+</html>