Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Stevenson2007-10-26 21:54:11 +0000
committerDave Stevenson2007-10-26 21:54:11 +0000
commit5848dddc54c63006c7b2a208d2d3e0d03433557d (patch)
tree06301e5cdf7bce73b64c7f092072670274ab0890 /bundles
parentc14f1952ef56c2690f856cf1825071ba7c251cf8 (diff)
downloadrt.equinox.p2-5848dddc54c63006c7b2a208d2d3e0d03433557d.tar.gz
rt.equinox.p2-5848dddc54c63006c7b2a208d2d3e0d03433557d.tar.xz
rt.equinox.p2-5848dddc54c63006c7b2a208d2d3e0d03433557d.zip
Initial delivery of SAX XML Writer/Parser framework for XStream replacement. The metadata and artifact repository writers/parsers are included, but not currently used.
Diffstat (limited to 'bundles')
-rw-r--r--bundles/org.eclipse.equinox.p2.artifact.repository/.classpath2
-rw-r--r--bundles/org.eclipse.equinox.p2.artifact.repository/META-INF/MANIFEST.MF9
-rw-r--r--bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/ArtifactRepositoryIO.java517
-rw-r--r--bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/Messages.java31
-rw-r--r--bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/SimpleArtifactRepository.java24
-rw-r--r--bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/messages.properties15
-rw-r--r--bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/p2/artifact/repository/ArtifactDescriptor.java37
-rw-r--r--bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/p2/artifact/repository/IArtifactDescriptor.java9
-rw-r--r--bundles/org.eclipse.equinox.p2.core/META-INF/MANIFEST.MF3
-rw-r--r--bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/Messages.java13
-rw-r--r--bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/MultiStatus.java44
-rw-r--r--bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/MultiStatusUtil.java15
-rw-r--r--bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/OrderedProperties.java9
-rw-r--r--bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLConstants.java50
-rw-r--r--bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLParser.java729
-rw-r--r--bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLUtils.java144
-rw-r--r--bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLWriter.java348
-rw-r--r--bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/messages.properties13
-rw-r--r--bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/spi/p2/core/repository/AbstractRepository.java1
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator CDT bad.launch20
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator CDT.launch15
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator SDK.launch8
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.repository/.classpath2
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.repository/META-INF/MANIFEST.MF4
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/LocalMetadataRepository.java27
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/Messages.java4
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/MetadataRepositoryIO.java895
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/URLMetadataRepository.java31
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/messages.properties7
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/spi/p2/metadata/repository/AbstractMetadataRepository.java19
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/META-INF/MANIFEST.MF2
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/IInstallableUnit.java3
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/InstallableUnit.java53
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/InstallableUnitFragment.java16
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/RequiredCapability.java16
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/ResolvedInstallableUnit.java7
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/TouchpointData.java7
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/TestMetadataRepository.java11
38 files changed, 3058 insertions, 102 deletions
diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/.classpath b/bundles/org.eclipse.equinox.p2.artifact.repository/.classpath
index 7cdeb7319..ce7393340 100644
--- a/bundles/org.eclipse.equinox.p2.artifact.repository/.classpath
+++ b/bundles/org.eclipse.equinox.p2.artifact.repository/.classpath
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/CDC-1.1%Foundation-1.1"/>
+ <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/bundles/org.eclipse.equinox.p2.artifact.repository/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.artifact.repository/META-INF/MANIFEST.MF
index df592a14e..daa676b87 100644
--- a/bundles/org.eclipse.equinox.p2.artifact.repository/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.p2.artifact.repository/META-INF/MANIFEST.MF
@@ -10,8 +10,10 @@ Export-Package: org.eclipse.equinox.internal.p2.artifact.repository;x-friends:="
org.eclipse.equinox.p2.artifact.repository.processing,
org.eclipse.equinox.spi.p2.artifact.repository
Import-Package: com.thoughtworks.xstream,
- org.eclipse.core.runtime.preferences,
+ javax.xml.parsers,
+ org.eclipse.core.runtime.preferences;resolution:=optional,
org.eclipse.equinox.internal.p2.jarprocessor;resolution:=optional,
+ org.eclipse.equinox.internal.p2.metadata,
org.eclipse.equinox.p2.core.helpers,
org.eclipse.equinox.p2.core.location,
org.eclipse.equinox.p2.core.repository,
@@ -19,9 +21,12 @@ Import-Package: com.thoughtworks.xstream,
org.eclipse.equinox.p2.metadata,
org.eclipse.equinox.spi.p2.core.repository,
org.eclipse.osgi.internal.provisional.verifier,
+ org.eclipse.osgi.service.resolver;version="1.1.0",
+ org.eclipse.osgi.util;version="1.1.0",
org.osgi.framework;version="1.3.0",
org.osgi.service.prefs;version="1.1.0",
- org.osgi.util.tracker;version="1.3.0"
+ org.osgi.util.tracker;version="1.3.0",
+ org.xml.sax;resolution:=optional
Bundle-Activator: org.eclipse.equinox.internal.p2.artifact.repository.Activator
Eclipse-LazyStart: true
Bundle-RequiredExecutionEnvironment: CDC-1.1/Foundation-1.1,
diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/ArtifactRepositoryIO.java b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/ArtifactRepositoryIO.java
index 0c2208f40..e51af1740 100644
--- a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/ArtifactRepositoryIO.java
+++ b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/ArtifactRepositoryIO.java
@@ -12,24 +12,95 @@ package org.eclipse.equinox.internal.p2.artifact.repository;
import com.thoughtworks.xstream.XStream;
import java.io.*;
+import java.util.*;
+import javax.xml.parsers.ParserConfigurationException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.equinox.internal.p2.metadata.ArtifactKey;
+import org.eclipse.equinox.p2.artifact.repository.ArtifactDescriptor;
import org.eclipse.equinox.p2.artifact.repository.IArtifactRepository;
+import org.eclipse.equinox.p2.artifact.repository.processing.ProcessingStepDescriptor;
+import org.eclipse.equinox.p2.core.helpers.*;
import org.eclipse.equinox.p2.core.repository.RepositoryCreationException;
+import org.eclipse.equinox.p2.metadata.IArtifactKey;
+import org.eclipse.osgi.service.resolver.VersionRange;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Version;
+import org.xml.sax.*;
/**
- * This class reads and writes artifact repository
- * (eg. table of contents files);
+ * This class reads and writes artifact repository metadata
+ * (e.g. table of contents files);
*
* This class is not used for reading or writing the actual artifacts.
*
* The implementation currently uses XStream.
*/
+
+// TODO: this class should be renamed to SimpleArtifactRepositoryIO
+// when the use of XStream is eliminated.
+// TODO: Should a registration/factory mechanism be supported
+// for getting a repository reader/writer given a repository type
class ArtifactRepositoryIO {
/**
+ * Writes the given artifact repository to the stream.
+ * This method performs buffering, and closes the stream when finished.
+ *
+ * Persistence implementation using XStream
+ * @deprecated
+ */
+ public static void write(SimpleArtifactRepository repository, OutputStream output) {
+ XStream stream = new XStream();
+ OutputStream bufferedOutput = null;
+ try {
+ try {
+ bufferedOutput = new BufferedOutputStream(output);
+ stream.toXML(repository, bufferedOutput);
+ } finally {
+ if (bufferedOutput != null) {
+ bufferedOutput.close();
+ }
+ }
+ } catch (FileNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Write the given SimpleArtifactRrepository to the given stream.
+ * This method closes the stream when finished.
+ */
+ public void writeNew(SimpleArtifactRepository repository, OutputStream output) {
+ OutputStream bufferedOutput = null;
+ try {
+ try {
+ bufferedOutput = new BufferedOutputStream(output);
+ Writer repositoryWriter = new Writer(bufferedOutput);
+ repositoryWriter.write(repository);
+ } finally {
+ if (bufferedOutput != null) {
+ bufferedOutput.close();
+ }
+ }
+ } catch (IOException ioe) {
+ // TODO shouldn't this throw a core exception?
+ ioe.printStackTrace();
+ }
+ }
+
+ /**
* Reads the artifact repository from the given stream,
* and returns the contained array of abstract artifact repositories.
*
* This method performs buffering, and closes the stream when finished.
+ *
+ * Persistence implementation using XStream
+ * @deprecated
*/
public static IArtifactRepository read(InputStream input) throws RepositoryCreationException {
XStream stream = new XStream();
@@ -48,27 +119,439 @@ class ArtifactRepositoryIO {
}
/**
- * Writes the given artifact repository to the stream.
- * This method performs buffering, and closes the stream when finished.
+ * Construct a SimpleArtifactRepository by reading from the given stream.
+ * This method closes the stream when finished.
*/
- public static void write(IArtifactRepository repository, OutputStream output) {
- XStream stream = new XStream();
- OutputStream bufferedOutput = null;
+ public SimpleArtifactRepository readNew(InputStream input) throws RepositoryCreationException {
+ BufferedInputStream bufferedInput = null;
try {
try {
- bufferedOutput = new BufferedOutputStream(output);
- stream.toXML(repository, bufferedOutput);
+ bufferedInput = new BufferedInputStream(input);
+ Parser repositoryParser = new Parser(Activator.getContext(), Activator.ID);
+ repositoryParser.parse(input);
+ if (!repositoryParser.isValidXML()) {
+ throw new RepositoryCreationException(new CoreException(repositoryParser.getStatus()));
+ }
+ return repositoryParser.getRepository();
} finally {
- if (bufferedOutput != null) {
- bufferedOutput.close();
+ if (bufferedInput != null)
+ bufferedInput.close();
+ }
+ } catch (IOException ioe) {
+ throw new RepositoryCreationException(ioe);
+ }
+ }
+
+ private interface XMLConstants extends org.eclipse.equinox.p2.core.helpers.XMLConstants {
+
+ // Constants defining the structure of the XML for a SimpleArtifactRepository
+
+ // A format version number for simple artifact repository XML.
+ public static final String XML_VERSION = "0.0.1"; //$NON-NLS-1$
+ public static final Version CURRENT_VERSION = new Version(XML_VERSION);
+ public static final VersionRange XML_TOLERANCE = new VersionRange(CURRENT_VERSION, true, CURRENT_VERSION, true);
+
+ // Constants for processing instructions
+ public static final String PI_REPOSITORY_TARGET = "artifactRepository"; //$NON-NLS-1$
+ public static XMLWriter.ProcessingInstruction[] PI_DEFAULTS = new XMLWriter.ProcessingInstruction[] {XMLWriter.ProcessingInstruction.makeClassVersionInstruction(PI_REPOSITORY_TARGET, SimpleArtifactRepository.class, CURRENT_VERSION)};
+
+ // Constants for artifact repository elements
+ public static final String REPOSITORY_ELEMENT = "repository"; //$NON-NLS-1$
+ public static final String MAPPING_RULES_ELEMENT = "mappings"; //$NON-NLS-1$
+ public static final String MAPPING_RULE_ELEMENT = "rule"; //$NON-NLS-1$
+ public static final String ARTIFACTS_ELEMENT = "artifacts"; //$NON-NLS-1$
+ public static final String ARTIFACT_ELEMENT = "artifact"; //$NON-NLS-1$
+ public static final String PROCESSING_STEPS_ELEMENT = "processing"; //$NON-NLS-1$
+ public static final String PROCESSING_STEP_ELEMENT = "step"; //$NON-NLS-1$
+
+ // Constants for attributes of artifact repository elements
+ public static final String VERIFY_SIGNATURE_ATTRIBUTE = "verify"; //$NON-NLS-1$
+
+ public static final String MAPPING_RULE_FILTER_ATTRIBUTE = "filter"; //$NON-NLS-1$
+ public static final String MAPPING_RULE_OUTPUT_ATTRIBUTE = "output"; //$NON-NLS-1$
+
+ public static final String ARTIFACT_NAMESPACE_ATTRIBUTE = NAMESPACE_ATTRIBUTE;
+ public static final String ARTIFACT_CLASSIFIER_ATTRIBUTE = CLASSIFIER_ATTRIBUTE;
+
+ public static final String STEP_DATA_ATTRIBUTE = "data"; //$NON-NLS-1$
+ public static final String STEP_REQUIRED_ATTRIBUTE = "required"; //$NON-NLS-1$
+ }
+
+ // XML writer for a SimpleArtifactRepository
+ protected class Writer extends XMLWriter implements XMLConstants {
+
+ public Writer(OutputStream output) throws IOException {
+ super(output, PI_DEFAULTS);
+ }
+
+ /**
+ * Write the given artifact repository to the output stream.
+ */
+ public void write(SimpleArtifactRepository repository) {
+ start(REPOSITORY_ELEMENT);
+ attribute(NAME_ATTRIBUTE, repository.getName());
+ attribute(TYPE_ATTRIBUTE, repository.getType());
+ attribute(VERSION_ATTRIBUTE, repository.getVersion());
+ attributeOptional(PROVIDER_ATTRIBUTE, repository.getProvider());
+ attributeOptional(DESCRIPTION_ATTRIBUTE, repository.getDescription()); // TODO: could be cdata?
+ attribute(VERIFY_SIGNATURE_ATTRIBUTE, repository.getSignatureVerification(), false);
+
+ writeProperties(repository.getProperties());
+ writeMappingRules(repository.getRules());
+ writeArtifacts(repository.getDescriptors());
+
+ end(REPOSITORY_ELEMENT);
+ flush();
+ }
+
+ private void writeMappingRules(String[][] rules) {
+ if (rules.length > 0) {
+ start(MAPPING_RULES_ELEMENT);
+ attribute(COLLECTION_SIZE_ATTRIBUTE, rules.length);
+ for (int i = 0; i < rules.length; i++) {
+ start(MAPPING_RULE_ELEMENT);
+ attribute(MAPPING_RULE_FILTER_ATTRIBUTE, rules[i][0]);
+ attribute(MAPPING_RULE_OUTPUT_ATTRIBUTE, rules[i][1]);
+ end(MAPPING_RULE_ELEMENT);
+ }
+ end(MAPPING_RULES_ELEMENT);
+ }
+ }
+
+ private void writeArtifacts(Set artifactDescriptors) {
+ start(ARTIFACTS_ELEMENT);
+ attribute(COLLECTION_SIZE_ATTRIBUTE, artifactDescriptors.size());
+ for (Iterator iter = artifactDescriptors.iterator(); iter.hasNext();) {
+ ArtifactDescriptor descriptor = (ArtifactDescriptor) iter.next();
+ IArtifactKey key = descriptor.getArtifactKey();
+ start(ARTIFACT_ELEMENT);
+ attribute(ARTIFACT_NAMESPACE_ATTRIBUTE, key.getNamespace());
+ attribute(ARTIFACT_CLASSIFIER_ATTRIBUTE, key.getClassifier());
+ attribute(ID_ATTRIBUTE, key.getId());
+ attribute(VERSION_ATTRIBUTE, key.getVersion());
+ writeProcessingSteps(descriptor.getProcessingSteps());
+ writeProperties(descriptor.getProperties());
+ end(ARTIFACT_ELEMENT);
+ }
+ end(ARTIFACTS_ELEMENT);
+ }
+
+ private void writeProcessingSteps(ProcessingStepDescriptor[] processingSteps) {
+ if (processingSteps.length > 0) {
+ start(PROCESSING_STEPS_ELEMENT);
+ attribute(COLLECTION_SIZE_ATTRIBUTE, processingSteps.length);
+ for (int i = 0; i < processingSteps.length; i++) {
+ start(PROCESSING_STEP_ELEMENT);
+ attribute(ID_ATTRIBUTE, processingSteps[i].getProcessorId());
+ attribute(STEP_DATA_ATTRIBUTE, processingSteps[i].getData());
+ attribute(STEP_REQUIRED_ATTRIBUTE, processingSteps[i].isRequired());
+ end(PROCESSING_STEP_ELEMENT);
+ }
+ end(PROCESSING_STEPS_ELEMENT);
+ }
+ }
+ }
+
+ /*
+ * Parser for the contents of a SimpleArtifactRepository,
+ * as written by the Writer class.
+ */
+ private class Parser extends XMLParser implements XMLConstants {
+
+ private SimpleArtifactRepository theRepository = null;
+
+ public Parser(BundleContext context, String bundleId) {
+ super(context, bundleId);
+ }
+
+ public void parse(File file) throws IOException {
+ parse(new FileInputStream(file));
+ }
+
+ public synchronized void parse(InputStream stream) throws IOException {
+ this.status = null;
+ try {
+ // TODO: currently not caching the parser since we make no assumptions
+ // or restrictions on concurrent parsing
+ getParser();
+ RepositoryHandler repositoryHandler = new RepositoryHandler();
+ xmlReader.setContentHandler(new RepositoryDocHandler(REPOSITORY_ELEMENT, repositoryHandler));
+ xmlReader.parse(new InputSource(stream));
+ if (isValidXML()) {
+ theRepository = repositoryHandler.getRepository();
+ }
+ } catch (SAXException e) {
+ throw new IOException(e.getMessage());
+ } catch (ParserConfigurationException e) {
+ throw new IOException(e.getMessage());
+ } finally {
+ stream.close();
+ }
+ }
+
+ public SimpleArtifactRepository getRepository() {
+ return theRepository;
+ }
+
+ protected Object getRootObject() {
+ return theRepository;
+ }
+
+ private final class RepositoryDocHandler extends DocHandler {
+
+ public RepositoryDocHandler(String rootName, RootHandler rootHandler) {
+ super(rootName, rootHandler);
+ }
+
+ public void ProcessingInstruction(String target, String data) throws SAXException {
+ if (PI_REPOSITORY_TARGET.equalsIgnoreCase(target)) {
+ // TODO: should the root handler be constructed based on class
+ // via an extension registry mechanism?
+ // String clazz = extractPIClass(data);
+ // and
+ // TODO: version tolerance by extension
+ Version repositoryVersion = extractPIVersion(target, data);
+ if (!XML_TOLERANCE.isIncluded(repositoryVersion)) {
+ throw new SAXException(NLS.bind(Messages.SimpleArtifactRepositoryIO_Parser_Has_Incompatible_Version, repositoryVersion, XML_TOLERANCE));
+ }
+ }
+ }
+
+ }
+
+ private final class RepositoryHandler extends RootHandler {
+
+ private final String[] required = new String[] {NAME_ATTRIBUTE, TYPE_ATTRIBUTE, VERSION_ATTRIBUTE};
+ private final String[] optional = new String[] {DESCRIPTION_ATTRIBUTE, PROVIDER_ATTRIBUTE, VERIFY_SIGNATURE_ATTRIBUTE};
+
+ private String[] attrValues = new String[required.length + optional.length];
+
+ private MappingRulesHandler mappingRulesHandler = null;
+ private PropertiesHandler propertiesHandler = null;
+ private ArtifactsHandler artifactsHandler = null;
+
+ private SimpleArtifactRepository repository = null;
+
+ public RepositoryHandler() {
+ super();
+ }
+
+ public SimpleArtifactRepository getRepository() {
+ return repository;
+ }
+
+ protected void handleRootAttributes(Attributes attributes) {
+ attrValues = parseAttributes(attributes, required, optional);
+ attrValues[2] = checkVersion(REPOSITORY_ELEMENT, VERSION_ATTRIBUTE, attrValues[2]).toString();
+ attrValues[5] = checkBoolean(REPOSITORY_ELEMENT, VERIFY_SIGNATURE_ATTRIBUTE, attrValues[5], false).toString();
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (MAPPING_RULES_ELEMENT.equalsIgnoreCase(name)) {
+ if (mappingRulesHandler == null) {
+ mappingRulesHandler = new MappingRulesHandler(this, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else if (ARTIFACTS_ELEMENT.equalsIgnoreCase(name)) {
+ if (artifactsHandler == null) {
+ artifactsHandler = new ArtifactsHandler(this, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else if (PROPERTIES_ELEMENT.equalsIgnoreCase(name)) {
+ if (propertiesHandler == null) {
+ propertiesHandler = new PropertiesHandler(this, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+
+ protected void finished() {
+ if (isValidXML()) {
+ String[][] mappingRules = (mappingRulesHandler == null ? new String[0][0] //
+ : mappingRulesHandler.getMappingRules());
+ OrderedProperties properties = (propertiesHandler == null ? new OrderedProperties(0) //
+ : propertiesHandler.getProperties());
+ Set artifacts = (artifactsHandler == null ? new HashSet(0) //
+ : artifactsHandler.getArtifacts());
+ boolean verifySignature = (attrValues[5] == null ? false //
+ : new Boolean(attrValues[5]).booleanValue());
+ repository = new SimpleArtifactRepository(attrValues[0], attrValues[1], attrValues[2], attrValues[3], //
+ attrValues[4], verifySignature, artifacts, mappingRules, properties);
}
}
- } catch (FileNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
}
+
+ protected class MappingRulesHandler extends AbstractHandler {
+
+ private List mappingRules;
+
+ public MappingRulesHandler(AbstractHandler parentHandler, Attributes attributes) {
+ super(parentHandler, MAPPING_RULES_ELEMENT);
+ String size = parseOptionalAttribute(attributes, COLLECTION_SIZE_ATTRIBUTE);
+ mappingRules = (size != null ? new ArrayList(new Integer(size).intValue()) : new ArrayList(4));
+ }
+
+ public String[][] getMappingRules() {
+ String[][] rules = new String[mappingRules.size()][2];
+ for (int index = 0; index < mappingRules.size(); index++) {
+ String[] ruleAttributes = (String[]) mappingRules.get(index);
+ rules[index] = ruleAttributes;
+ }
+ return rules;
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equalsIgnoreCase(MAPPING_RULE_ELEMENT)) {
+ new MappingRuleHandler(this, attributes, mappingRules);
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+ }
+
+ protected class MappingRuleHandler extends AbstractHandler {
+
+ private final String[] required = new String[] {MAPPING_RULE_FILTER_ATTRIBUTE, MAPPING_RULE_OUTPUT_ATTRIBUTE};
+
+ public MappingRuleHandler(AbstractHandler parentHandler, Attributes attributes, List mappingRules) {
+ super(parentHandler, MAPPING_RULE_ELEMENT);
+ mappingRules.add(parseRequiredAttributes(attributes, required));
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ invalidElement(name, attributes);
+ }
+ }
+
+ protected class ArtifactsHandler extends AbstractHandler {
+
+ private Set artifacts;
+
+ public ArtifactsHandler(AbstractHandler parentHandler, Attributes attributes) {
+ super(parentHandler, ARTIFACTS_ELEMENT);
+ String size = parseOptionalAttribute(attributes, COLLECTION_SIZE_ATTRIBUTE);
+ artifacts = (size != null ? new LinkedHashSet(new Integer(size).intValue()) : new LinkedHashSet(4));
+ }
+
+ public Set getArtifacts() {
+ return artifacts;
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equalsIgnoreCase(ARTIFACT_ELEMENT)) {
+ new ArtifactHandler(this, attributes, artifacts);
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+ }
+
+ protected class ArtifactHandler extends AbstractHandler {
+
+ private final String[] required = new String[] {ARTIFACT_NAMESPACE_ATTRIBUTE, ARTIFACT_CLASSIFIER_ATTRIBUTE, ID_ATTRIBUTE, VERSION_ATTRIBUTE};
+
+ private Set artifacts;
+ ArtifactDescriptor currentArtifact = null;
+
+ private PropertiesHandler propertiesHandler = null;
+ private ProcessingStepsHandler processingStepsHandler = null;
+
+ public ArtifactHandler(AbstractHandler parentHandler, Attributes attributes, Set artifacts) {
+ super(parentHandler, ARTIFACT_ELEMENT);
+ this.artifacts = artifacts;
+ String[] values = parseRequiredAttributes(attributes, required);
+ Version version = checkVersion(ARTIFACT_ELEMENT, VERSION_ATTRIBUTE, values[3]);
+ // TODO: resolve access restriction on ArtifactKey construction
+ currentArtifact = new ArtifactDescriptor(new ArtifactKey(values[0], values[1], values[2], version));
+ }
+
+ public ArtifactDescriptor getArtifact() {
+ return currentArtifact;
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (PROCESSING_STEPS_ELEMENT.equalsIgnoreCase(name)) {
+ if (processingStepsHandler == null) {
+ processingStepsHandler = new ProcessingStepsHandler(this, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else if (PROPERTIES_ELEMENT.equalsIgnoreCase(name)) {
+ if (propertiesHandler == null) {
+ propertiesHandler = new PropertiesHandler(this, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+
+ protected void finished() {
+ if (isValidXML() && currentArtifact != null) {
+ OrderedProperties properties = (propertiesHandler == null ? new OrderedProperties(0) //
+ : propertiesHandler.getProperties());
+ currentArtifact.addProperties(properties);
+ ProcessingStepDescriptor[] processingSteps = (processingStepsHandler == null ? new ProcessingStepDescriptor[0] //
+ : processingStepsHandler.getProcessingSteps());
+ currentArtifact.setProcessingSteps(processingSteps);
+ artifacts.add(currentArtifact);
+ }
+ }
+ }
+
+ protected class ProcessingStepsHandler extends AbstractHandler {
+
+ private List processingSteps;
+
+ public ProcessingStepsHandler(AbstractHandler parentHandler, Attributes attributes) {
+ super(parentHandler, PROCESSING_STEPS_ELEMENT);
+ String size = parseOptionalAttribute(attributes, COLLECTION_SIZE_ATTRIBUTE);
+ processingSteps = (size != null ? new ArrayList(new Integer(size).intValue()) : new ArrayList(4));
+ }
+
+ public ProcessingStepDescriptor[] getProcessingSteps() {
+ return (ProcessingStepDescriptor[]) processingSteps.toArray(new ProcessingStepDescriptor[processingSteps.size()]);
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equalsIgnoreCase(PROCESSING_STEP_ELEMENT)) {
+ new ProcessingStepHandler(this, attributes, processingSteps);
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+ }
+
+ protected class ProcessingStepHandler extends AbstractHandler {
+
+ private final String[] required = new String[] {ID_ATTRIBUTE, STEP_DATA_ATTRIBUTE, STEP_REQUIRED_ATTRIBUTE};
+
+ public ProcessingStepHandler(AbstractHandler parentHandler, Attributes attributes, List processingSteps) {
+ super(parentHandler, PROCESSING_STEP_ELEMENT);
+ String[] attributeValues = parseRequiredAttributes(attributes, required);
+ processingSteps.add(new ProcessingStepDescriptor(attributeValues[0], attributeValues[1], checkBoolean(PROCESSING_STEP_ELEMENT, STEP_REQUIRED_ATTRIBUTE, attributeValues[2]).booleanValue()));
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ invalidElement(name, attributes);
+ }
+ }
+
+ protected String getErrorMessage() {
+ return Messages.SimpleArtifactRepositoryIO_Parser_Error_Parsing_Repository;
+ }
+
+ public String toString() {
+ // TODO:
+ return null;
+ }
+
}
+
}
diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/Messages.java b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/Messages.java
new file mode 100644
index 000000000..18c01183e
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/Messages.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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 Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.artifact.repository;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.equinox.internal.p2.artifact.repository.messages"; //$NON-NLS-1$
+
+ static {
+ // initialize resource bundles
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ // Do not instantiate
+ }
+
+ public static String SimpleArtifactRepositoryIO_Parser_Error_Parsing_Repository;
+ public static String SimpleArtifactRepositoryIO_Parser_Has_Incompatible_Version;
+
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/SimpleArtifactRepository.java b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/SimpleArtifactRepository.java
index 5324f3dfa..bb8c7b0b3 100644
--- a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/SimpleArtifactRepository.java
+++ b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/SimpleArtifactRepository.java
@@ -16,6 +16,8 @@ import org.eclipse.core.runtime.*;
import org.eclipse.equinox.p2.artifact.repository.*;
import org.eclipse.equinox.p2.artifact.repository.processing.ProcessingStep;
import org.eclipse.equinox.p2.artifact.repository.processing.ProcessingStepHandler;
+import org.eclipse.equinox.p2.core.helpers.MultiStatus;
+import org.eclipse.equinox.p2.core.helpers.OrderedProperties;
import org.eclipse.equinox.p2.core.repository.IRepository;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import org.eclipse.equinox.spi.p2.artifact.repository.AbstractArtifactRepository;
@@ -35,7 +37,7 @@ public class SimpleArtifactRepository extends AbstractArtifactRepository impleme
protected String[][] mappingRules = DEFAULT_MAPPING_RULES;
protected Set artifactDescriptors = new HashSet();
private boolean signatureVerification = false;
- private BlobStore blobStore;
+ private transient BlobStore blobStore;
public static URL getActualLocation(URL base) {
String spec = base.toExternalForm();
@@ -71,6 +73,14 @@ public class SimpleArtifactRepository extends AbstractArtifactRepository impleme
blobStore = new BlobStore(getBlobStoreLocation(location), 128);
}
+ public SimpleArtifactRepository(String name, String type, String version, String description, String provider, boolean verifySignature, Set artifacts, String[][] mappingRules, OrderedProperties properties) {
+ super(name, type, version, null, description, provider);
+ signatureVerification = verifySignature;
+ this.artifactDescriptors.addAll(artifacts);
+ this.mappingRules = mappingRules;
+ this.properties.putAll(properties);
+ }
+
private IStatus getArtifact(ArtifactRequest request, IProgressMonitor monitor) {
request.setSourceRepository(this);
request.perform(monitor);
@@ -171,7 +181,7 @@ public class SimpleArtifactRepository extends AbstractArtifactRepository impleme
public File getArtifactFile(IArtifactDescriptor descriptor) {
String result = getLocation(descriptor);
- if (result == null || !result.startsWith("file:"))
+ if (result == null || !result.startsWith("file:")) //$NON-NLS-1$
return null;
return new File(result.substring(5));
}
@@ -308,7 +318,8 @@ public class SimpleArtifactRepository extends AbstractArtifactRepository impleme
public void save() {
try {
- FileOutputStream os = new FileOutputStream(getActualLocation(location).getFile());
+ URL actualLocation = getActualLocation(location);
+ FileOutputStream os = new FileOutputStream(actualLocation.getFile());
ArtifactRepositoryIO.write(this, os);
} catch (IOException e) {
e.printStackTrace();
@@ -341,7 +352,7 @@ public class SimpleArtifactRepository extends AbstractArtifactRepository impleme
// Make sure that the file does not exist and that the parents do
File outputFile = new File(file);
if (outputFile.exists())
- System.err.println("Artifact repository out of synch. Overwriting " + outputFile.getAbsoluteFile());
+ System.err.println("Artifact repository out of synch. Overwriting " + outputFile.getAbsoluteFile()); //$NON-NLS-1$
if (!outputFile.getParentFile().exists() && !outputFile.getParentFile().mkdirs())
// TODO: Log an error, or throw an exception?
return null;
@@ -434,6 +445,10 @@ public class SimpleArtifactRepository extends AbstractArtifactRepository impleme
}
}
+ public boolean getSignatureVerification() {
+ return signatureVerification;
+ }
+
public void setSignatureVerification(boolean value) {
signatureVerification = value;
}
@@ -449,4 +464,5 @@ public class SimpleArtifactRepository extends AbstractArtifactRepository impleme
public boolean isModifiable() {
return true;
}
+
}
diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/messages.properties b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/messages.properties
new file mode 100644
index 000000000..bc3cf48db
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/repository/messages.properties
@@ -0,0 +1,15 @@
+###############################################################################
+# 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 Corporation - initial API and implementation
+###############################################################################
+
+SimpleArtifactRepositoryIO_Parser_Error_Parsing_Repository=\
+ Error parsing simple artifact repository
+SimpleArtifactRepositoryIO_Parser_Has_Incompatible_Version=\
+ Simple artifact repository has incompatible version {0}; expected {1} \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/p2/artifact/repository/ArtifactDescriptor.java b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/p2/artifact/repository/ArtifactDescriptor.java
index 207848333..167cd5476 100644
--- a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/p2/artifact/repository/ArtifactDescriptor.java
+++ b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/p2/artifact/repository/ArtifactDescriptor.java
@@ -10,8 +10,11 @@
*******************************************************************************/
package org.eclipse.equinox.p2.artifact.repository;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Map;
import org.eclipse.equinox.p2.artifact.repository.processing.ProcessingStepDescriptor;
+import org.eclipse.equinox.p2.core.helpers.OrderedProperties;
+import org.eclipse.equinox.p2.core.helpers.UnmodifiableProperties;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
/**
@@ -26,22 +29,21 @@ public class ArtifactDescriptor implements IArtifactDescriptor {
// The list of post processing steps that must be applied one the artifact once it
// has been downloaded (e.g, unpack, then md5 checksum, then...)
protected ProcessingStepDescriptor[] processingSteps = EMPTY_STEPS;
- protected Map properties = new HashMap(2);
+
+ protected OrderedProperties properties = new OrderedProperties();
+
protected transient IArtifactRepository repository;
- //QUESTION: Do we need any description or user readable name
+ // QUESTION: Do we need any description or user readable name
public ArtifactDescriptor(IArtifactDescriptor base) {
super();
key = base.getArtifactKey();
processingSteps = base.getProcessingSteps();
+ properties.putAll(base.getProperties());
repository = base.getRepository();
- // TODO figure out a better way to copy the properties
- setProperty(IArtifactDescriptor.ARTIFACT_MD5, base.getProperty(IArtifactDescriptor.ARTIFACT_MD5));
- setProperty(IArtifactDescriptor.ARTIFACT_SIZE, base.getProperty(IArtifactDescriptor.ARTIFACT_SIZE));
- setProperty(IArtifactDescriptor.DOWNLOAD_MD5, base.getProperty(IArtifactDescriptor.DOWNLOAD_MD5));
- setProperty(IArtifactDescriptor.DOWNLOAD_SIZE, base.getProperty(IArtifactDescriptor.DOWNLOAD_SIZE));
- setProperty(IArtifactDescriptor.FORMAT, base.getProperty(IArtifactDescriptor.FORMAT));
+ // TODO this property is hardcoded for the blob store.
+ // setProperty("artifact.uuid", base.getProperty("artifact.uuid"));
}
public ArtifactDescriptor(ArtifactDescriptor base) {
@@ -61,8 +63,8 @@ public class ArtifactDescriptor implements IArtifactDescriptor {
return key;
}
- public String getProperty(String key) {
- return (String) properties.get(key);
+ public String getProperty(String propertyKey) {
+ return (String) properties.get(propertyKey);
}
public void setProperty(String key, String value) {
@@ -72,6 +74,18 @@ public class ArtifactDescriptor implements IArtifactDescriptor {
properties.put(key, value);
}
+ public void addProperties(OrderedProperties additionalProperties) {
+ properties.putAll(additionalProperties);
+ }
+
+ /**
+ * Returns a read-only collection of the properties of the artifact descriptor.
+ * @return the properties of this artifact descriptor.
+ */
+ public Map getProperties() {
+ return new UnmodifiableProperties(properties);
+ }
+
public ProcessingStepDescriptor[] getProcessingSteps() {
return processingSteps;
}
@@ -137,4 +151,5 @@ public class ArtifactDescriptor implements IArtifactDescriptor {
return "canonical: " + key.toString(); //$NON-NLS-1$
return format + ": " + key.toString(); //$NON-NLS-1$
}
+
} \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/p2/artifact/repository/IArtifactDescriptor.java b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/p2/artifact/repository/IArtifactDescriptor.java
index 6c0271059..eb12b8429 100644
--- a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/p2/artifact/repository/IArtifactDescriptor.java
+++ b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/p2/artifact/repository/IArtifactDescriptor.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.equinox.p2.artifact.repository;
+import java.util.Map;
import org.eclipse.equinox.p2.artifact.repository.processing.ProcessingStepDescriptor;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
@@ -30,11 +31,17 @@ public interface IArtifactDescriptor {
/**
* Return the value of the given property in this descriptor <code>null</code>
* is returned if no such property exists
- * @param key the proerty key to look for
+ * @param key the property key to look for
* @return the value of the given property or <code>null</code>
*/
public abstract String getProperty(String key);
+ /**
+ * Returns a read-only collection of the properties of the artifact descriptor.
+ * @return the properties of this artifact descriptor.
+ */
+ public Map getProperties();
+
/**
* Return the list of processing steps associated with this descriptor.
* An empty set of steps implies that this descriptor describes a complete
diff --git a/bundles/org.eclipse.equinox.p2.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.core/META-INF/MANIFEST.MF
index 7d2af04c9..2aad67f79 100644
--- a/bundles/org.eclipse.equinox.p2.core/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.p2.core/META-INF/MANIFEST.MF
@@ -14,7 +14,8 @@ Import-Package: com.thoughtworks.xstream,
org.eclipse.osgi.service.resolver;version="1.1.0",
org.eclipse.osgi.util;version="1.0.0",
org.osgi.framework;version="1.3.0",
- org.osgi.util.tracker;version="1.3.3"
+ org.osgi.util.tracker;version="1.3.3",
+ org.xml.sax
Export-Package: org.eclipse.equinox.internal.p2.core;x-internal:=true,
org.eclipse.equinox.p2.core,
org.eclipse.equinox.p2.core.eventbus,
diff --git a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/Messages.java b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/Messages.java
index 2360b0e7a..65f733618 100644
--- a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/Messages.java
+++ b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/Messages.java
@@ -24,4 +24,17 @@ public class Messages extends NLS {
public static String Util_Invalid_Zip_File_Format;
public static String Util_Error_Unzipping;
+ public static String XMLParser_No_SAX_Parser;
+ public static String XMLParser_Error_At_Line;
+ public static String XMLParser_Error_At_Line_Column;
+ public static String XMLParser_Error_At_Name_Line;
+ public static String XMLParser_Error_At_Name_Line_Column;
+ public static String XMLParser_Missing_Required_Attribute;
+ public static String XMLParser_Unexpected_Attribute;
+ public static String XMLParser_Illegal_Value_For_Attribute;
+ public static String XMLParser_Unexpected_Element;
+ public static String XMLParser_Duplicate_Element;
+ public static String XMLParser_Unexpected_Character_Data;
+ public static String XMLParser_Element_Not_Allowed;
+
}
diff --git a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/MultiStatus.java b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/MultiStatus.java
index 58b44901c..eabca5077 100644
--- a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/MultiStatus.java
+++ b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/MultiStatus.java
@@ -11,20 +11,20 @@
package org.eclipse.equinox.p2.core.helpers;
import java.util.*;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.*;
/**
* An variation of the MultiStatus. Note that this does not
* extend runtime.MultiStatus, instead it extends Status, because
* the purpose of this class is to avoid a few shortcomings of
* runtime.MultiStatus. This is different as follows:
- * - Add only non-ok status as child (this prevents bloat).
+ * - Add only non-OK status as child (this prevents bloat).
* - Children is a list instead of an array; helps when add()
* is called more often than getChildren()
*/
public class MultiStatus extends Status {
- public final static String bundleId = "org.eclipse.equinox.p2";
+
+ public final static String bundleId = "org.eclipse.equinox.p2"; //$NON-NLS-1$
public static final int STATUS_CODE_SUCCESS = 0;
// Use ArrayList rather than List so ensureCapacity() is available.
@@ -68,21 +68,21 @@ public class MultiStatus extends Status {
}
/**
- * A Multi-Status with an exception.
+ * A MultiStatus with an exception.
*/
public MultiStatus(int code, String msg, Throwable exception) {
this(code, msg, null, exception);
}
/**
- * A Multi-Status with children.
+ * A MultiStatus with children.
*/
public MultiStatus(int code, String msg, IStatus[] nested, Throwable exception) {
this(OK, bundleId, code, msg, nested, exception);
}
/**
- * For creation from outside of the default plugin.
+ * For creation from outside of the default plug-in.
*/
public MultiStatus(String pluginId, int code, String msg, Throwable exception) {
this(OK, pluginId, code, msg, null, exception);
@@ -96,7 +96,7 @@ public class MultiStatus extends Status {
}
/**
- * A Multi-Status with everything.
+ * A MultiStatus with everything.
*/
public MultiStatus(int severity, String pluginId, int code, String msg, IStatus[] nested, Throwable exception) {
super(severity, pluginId, code, msg, exception);
@@ -113,7 +113,7 @@ public class MultiStatus extends Status {
}
/**
- * Does this status indicate an error or cancelation.
+ * Does this status indicate an error or cancellation.
*/
public boolean isErrorOrCancel() {
return matches(ERROR | CANCEL);
@@ -164,9 +164,9 @@ public class MultiStatus extends Status {
/**
* Adds the children of the given status as its own
- * chldren. This internally uses add(IStatus). This
+ * children. This internally uses add(IStatus). This
* guards against a null status.
- * @param status A multi-status IStatus object whose children
+ * @param status A MultiStatus IStatus object whose children
* are to be added to this children.
*/
public void addAll(IStatus status) {
@@ -181,6 +181,26 @@ public class MultiStatus extends Status {
}
}
+ /**
+ * Merges the given status into this MultiStatus.
+ * Equivalent to <code>add(status)</code> if the
+ * given status is not a mMultiStatus.
+ * Equivalent to <code>addAll(status)</code> if the
+ * given status is a MultiStatus.
+ *
+ * @param status the status to merge into this one
+ * @see #add(IStatus)
+ * @see #addAll(IStatus)
+ */
+ public void merge(IStatus status) {
+ Assert.isLegal(status != null);
+ if (!status.isMultiStatus()) {
+ add(status);
+ } else {
+ addAll(status);
+ }
+ }
+
/*
* @see IStatus#getChildren()
*/
@@ -201,7 +221,7 @@ public class MultiStatus extends Status {
/**
* Collapses the children into a flat list.
- * If all the children are non-multi-status,
+ * If all the children are non-MultiStatus,
* this is essentially getChildren().
* @return An array of IStatus objects.
* @see #getChildren()
diff --git a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/MultiStatusUtil.java b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/MultiStatusUtil.java
index 0e2bb3800..6872493a9 100644
--- a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/MultiStatusUtil.java
+++ b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/MultiStatusUtil.java
@@ -65,8 +65,8 @@ public class MultiStatusUtil {
}
}
return sb.toString();
- } else
- return status.getMessage();
+ }
+ return status.getMessage();
}
public static List getStatusNodes(IStatus root) {
@@ -92,10 +92,8 @@ public class MultiStatusUtil {
}
private static IStatus newNonMultiStatus(IStatus status) {
- if (status.isMultiStatus())
- return new Status(status.getSeverity(), status.getPlugin(), status.getCode(), status.getMessage(), status.getException());
- else
- return status;
+ return (status.isMultiStatus() ? new Status(status.getSeverity(), status.getPlugin(), status.getCode(), status.getMessage(), status.getException()) //
+ : status);
}
private static void collectStatusNodes(IStatus root, List nodes) {
@@ -176,9 +174,7 @@ public class MultiStatusUtil {
}
private static boolean needsRecoding(IStatus status, IStatusRecoder recoder) {
- if (!status.isMultiStatus())
- return recoder.needsRecoding(status);
- else {
+ if (status.isMultiStatus()) {
if (recoder.needsRecoding(status))
return true;
IStatus[] children = status.getChildren();
@@ -189,6 +185,7 @@ public class MultiStatusUtil {
}
return false;
}
+ return recoder.needsRecoding(status);
}
private static IStatus doSingleRecode(IStatus status, IStatusRecoder recoder) {
diff --git a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/OrderedProperties.java b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/OrderedProperties.java
index 2c8e5b660..7fce86635 100644
--- a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/OrderedProperties.java
+++ b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/OrderedProperties.java
@@ -34,6 +34,11 @@ public class OrderedProperties implements Map {
super();
}
+ public OrderedProperties(int size) {
+ super();
+ propertyMap = new LinkedHashMap(size);
+ }
+
/**
* Set the property value.
* <p>
@@ -65,9 +70,7 @@ public class OrderedProperties implements Map {
}
public Collection getPropertyKeysCollection() {
- if (propertyMap == null)
- return Collections.EMPTY_LIST;
- return Collections.unmodifiableCollection(propertyMap.keySet());
+ return (propertyMap != null ? Collections.unmodifiableCollection(propertyMap.keySet()) : Collections.EMPTY_LIST);
}
public String[] getPropertyKeys() {
diff --git a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLConstants.java b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLConstants.java
new file mode 100644
index 000000000..be698b138
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLConstants.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * 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 Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.p2.core.helpers;
+
+public interface XMLConstants {
+
+ // Constants used in defining a default processing instruction
+ // including a class name and a version of the associated XML
+ // for some category of objects.
+ // e.g. <?category class='a.b.c.SomeClass' version='1.2.3'?>
+ //
+ public static final String PI_CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$
+ public static final String PI_VERSION_ATTRIBUTE = "version"; //$NON-NLS-1$
+
+ // Element and attribute names for a standard property collection.
+ // e.g. <properties size='1'>
+ // <property name='some_name' value='some_value'/>
+ // </properties>
+ public static final String PROPERTIES_ELEMENT = "properties"; //$NON-NLS-1$
+ public static final String PROPERTY_ELEMENT = "property"; //$NON-NLS-1$
+ public static final String PROPERTY_NAME_ATTRIBUTE = "name"; //$NON-NLS-1$
+ public static final String PROPERTY_VALUE_ATTRIBUTE = "value"; //$NON-NLS-1$
+
+ // Constants for the names of common general attributes
+ public static final String ID_ATTRIBUTE = "id"; //$NON-NLS-1$
+ public static final String TYPE_ATTRIBUTE = "type"; //$NON-NLS-1$
+ public static final String NAME_ATTRIBUTE = "name"; //$NON-NLS-1$
+ public static final String VERSION_ATTRIBUTE = "version"; //$NON-NLS-1$
+ public static final String VERSION_RANGE_ATTRIBUTE = "range"; //$NON-NLS-1$
+ public static final String NAMESPACE_ATTRIBUTE = "namespace"; //$NON-NLS-1$
+ public static final String CLASSIFIER_ATTRIBUTE = "classifier"; //$NON-NLS-1$
+ public static final String DESCRIPTION_ATTRIBUTE = "description"; //$NON-NLS-1$
+ public static final String PROVIDER_ATTRIBUTE = "provider"; //$NON-NLS-1$
+
+ // A constant for the name of an attribute of a collection or array element
+ // specifying the size or length
+ public static final String COLLECTION_SIZE_ATTRIBUTE = "size"; //$NON-NLS-1$
+
+ // A constant for an empty array of attribute names
+ public static String[] noAttributes = new String[0];
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLParser.java b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLParser.java
new file mode 100644
index 000000000..5db1860d6
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLParser.java
@@ -0,0 +1,729 @@
+/*******************************************************************************
+ * 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 Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.p2.core.helpers;
+
+import java.util.List;
+import java.util.regex.Pattern;
+import javax.xml.parsers.*;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.service.resolver.VersionRange;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Version;
+import org.osgi.util.tracker.ServiceTracker;
+import org.xml.sax.*;
+import org.xml.sax.helpers.DefaultHandler;
+
+public abstract class XMLParser extends DefaultHandler implements XMLConstants {
+
+ // TODO: support logging
+ // Get the logger associated with the class.
+ // protected abstract Logger getLogger();
+
+ // Get the root object that is being parsed.
+ protected abstract Object getRootObject();
+
+ // Get a generic parser error message for inclusion in an error status
+ protected abstract String getErrorMessage();
+
+ protected BundleContext context; // parser class bundle context
+ protected String bundleId; // parser class bundle id
+
+ protected XMLReader xmlReader; // the XML reader for the parser
+ protected ErrorHandler errorHandler; // the error handler for the parser
+
+ protected MultiStatus status = null; // accumulation of non-fatal errors
+ protected Locator locator = null; // document locator, if supported by the parser
+
+ private static ServiceTracker xmlTracker = null;
+
+ public XMLParser(BundleContext context, String pluginId) {
+ super();
+ this.context = context;
+ this.bundleId = pluginId;
+ }
+
+ /**
+ * Non-fatal errors accumulated during parsing.
+ */
+ public IStatus getStatus() {
+ return (status != null ? status : Status.OK_STATUS);
+ }
+
+ public boolean isValidXML() {
+ return (status == null || !status.isErrorOrCancel());
+ }
+
+ private static SAXParserFactory acquireXMLParsing(BundleContext context) {
+ if (xmlTracker == null) {
+ xmlTracker = new ServiceTracker(context, SAXParserFactory.class.getName(), null);
+ xmlTracker.open();
+ }
+ return (SAXParserFactory) xmlTracker.getService();
+ }
+
+ protected static void releaseXMLParsing() {
+ if (xmlTracker != null) {
+ xmlTracker.close();
+ }
+ }
+
+ protected SAXParser getParser() throws ParserConfigurationException, SAXException {
+ SAXParserFactory factory = acquireXMLParsing(this.context);
+ if (factory == null) {
+ throw new SAXException(Messages.XMLParser_No_SAX_Parser);
+ }
+ factory.setNamespaceAware(true);
+ factory.setValidating(true);
+ try {
+ factory.setFeature("http://xml.org/sax/features/string-interning", true); //$NON-NLS-1$
+ } catch (SAXException se) {
+ // some parsers may not support string interning
+ }
+ SAXParser theParser = factory.newSAXParser();
+ if (theParser == null) {
+ throw new SAXException(Messages.XMLParser_No_SAX_Parser);
+ }
+ xmlReader = theParser.getXMLReader();
+ return theParser;
+ }
+
+ public static String makeSimpleName(String localName, String qualifiedName) {
+ if (localName != null && localName.length() > 0) {
+ return localName;
+ }
+ int nameSpaceIndex = qualifiedName.indexOf(":"); //$NON-NLS-1$
+ return (nameSpaceIndex == -1 ? qualifiedName : qualifiedName.substring(nameSpaceIndex + 1));
+ }
+
+ /**
+ * Set the document locator for the parser
+ *
+ * @see org.xml.sax.ContentHandler#setDocumentLocator
+ */
+ public void setDocumentLocator(Locator docLocator) {
+ locator = docLocator;
+ }
+
+ /**
+ * Abstract base class for content handlers
+ */
+ protected abstract class AbstractHandler extends DefaultHandler {
+
+ protected ContentHandler parentHandler = null;
+ protected String elementHandled = null;
+
+ protected StringBuffer characters = null; // character data inside an element
+
+ public AbstractHandler() {
+ // Empty constructor for a root handler
+ }
+
+ public AbstractHandler(ContentHandler parentHandler) {
+ this.parentHandler = parentHandler;
+ xmlReader.setContentHandler(this);
+ }
+
+ public AbstractHandler(ContentHandler parentHandler, String elementHandled) {
+ this.parentHandler = parentHandler;
+ xmlReader.setContentHandler(this);
+ this.elementHandled = elementHandled;
+ }
+
+ /**
+ * Set the document locator for the parser
+ *
+ * @see org.xml.sax.ContentHandler#setDocumentLocator
+ */
+ public void setDocumentLocator(Locator docLocator) {
+ locator = docLocator;
+ }
+
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ finishCharacters();
+ String name = makeSimpleName(localName, qName);
+ trace(name, attributes);
+ startElement(name, attributes);
+ }
+
+ public abstract void startElement(String name, Attributes attributes) throws SAXException;
+
+ public void invalidElement(String name, Attributes attributes) {
+ unexpectedElement(this, name, attributes);
+ new IgnoringHandler(this);
+ }
+
+ public void endElement(String namespaceURI, String localName, String qName) {
+ // TODO: throw a bad state error if makeSimpleName(localName, qName) != elementHandled
+ finishCharacters();
+ finished();
+ // Restore the parent content handler
+ xmlReader.setContentHandler(parentHandler);
+ }
+
+ /**
+ * An implementation for startElement when there are no sub-elements
+ */
+ protected void noSubElements(String name, Attributes attributes) {
+ unexpectedElement(this, name, attributes);
+ // Create a new handler to ignore subsequent nested elements
+ new IgnoringHandler(this);
+ }
+
+ /*
+ * Save up character data until endElement or nested startElement
+ *
+ * @see org.xml.sax.ContentHandler#characters
+ */
+ public void characters(char[] chars, int start, int length) {
+ if (this.characters == null) {
+ this.characters = new StringBuffer();
+ }
+ this.characters.append(chars, start, length);
+ }
+
+ // Consume the characters accumulated in this.characters.
+ // Called before startElement or endElement
+ private String finishCharacters() {
+ // common case -- no characters or only whitespace
+ if (this.characters == null || this.characters.length() == 0) {
+ return null;
+ }
+ if (allWhiteSpace(this.characters)) {
+ this.characters.setLength(0);
+ return null;
+ }
+
+ // process the characters
+ try {
+ String trimmedChars = this.characters.toString().trim();
+ if (trimmedChars.length() == 0) {
+ // this shouldn't happen due to the test for allWhiteSpace above
+ System.err.println("Unexpected non-whitespace characters: " //$NON-NLS-1$
+ + trimmedChars);
+ return null;
+ }
+ processCharacters(trimmedChars);
+ return trimmedChars;
+ } finally {
+ this.characters.setLength(0);
+ }
+ }
+
+ // Method to override in the handler of an element with CDATA.
+ protected void processCharacters(String data) {
+ if (data.length() > 0) {
+ unexpectedCharacterData(this, data);
+ }
+ }
+
+ private boolean allWhiteSpace(StringBuffer sb) {
+ int length = sb.length();
+ for (int i = 0; i < length; i += 1) {
+ if (!Character.isWhitespace(sb.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Called when this element and all elements nested into it have been
+ * handled.
+ */
+ protected void finished() {
+ // Do nothing by default
+ }
+
+ /*
+ * A name used to identify the handler.
+ */
+ public String getName() {
+ return (elementHandled != null ? elementHandled : "NoName"); //$NON-NLS-1$
+ }
+
+ /**
+ * Parse the attributes of an element with a single required attribute.
+ */
+ protected String parseRequiredAttribute(Attributes attributes, String name) {
+ return parseRequiredAttributes(attributes, new String[] {name})[0];
+ }
+
+ /**
+ * Parse the attributes of an element with two required attributes.
+ */
+ protected String[] parseRequiredAttributes(Attributes attributes, String name1, String name2) {
+ return parseRequiredAttributes(attributes, new String[] {name1, name2});
+ }
+
+ /**
+ * Parse the attributes of an element with only required attributes.
+ */
+ protected String[] parseRequiredAttributes(Attributes attributes, String[] required) {
+ return parseAttributes(attributes, required, noAttributes);
+ }
+
+ /**
+ * Parse the attributes of an element with a single optional attribute.
+ */
+ protected String parseOptionalAttribute(Attributes attributes, String name) {
+ return parseAttributes(attributes, noAttributes, new String[] {name})[0];
+ }
+
+ /**
+ * Parse the attributes of an element, given the list of required and optional ones.
+ * Return values in same order, null for those not present.
+ * Report errors for missing required attributes or extra ones.
+ */
+ protected String[] parseAttributes(Attributes attributes, String[] required, String[] optional) {
+ String[] result = new String[required.length + optional.length];
+ for (int i = 0; i < attributes.getLength(); i += 1) {
+ String name = attributes.getLocalName(i);
+ String value = attributes.getValue(i).trim();
+ int j;
+ if ((j = indexOf(required, name)) >= 0) {
+ result[j] = value;
+ } else if ((j = indexOf(optional, name)) >= 0) {
+ result[required.length + j] = value;
+ } else {
+ unexpectedAttribute(elementHandled, name, value);
+ }
+ }
+ for (int i = 0; i < required.length; i += 1) {
+ checkRequiredAttribute(elementHandled, required[i], result[i]);
+ }
+ return result;
+ }
+
+ }
+
+ /**
+ * Handler for an XML document.
+ *
+ * Using the inelegant name 'DocHandler' to clearly distinguish
+ * this class from the deprecated org.xml.sax.DocumentHandler.
+ */
+ protected class DocHandler extends AbstractHandler {
+
+ RootHandler rootHandler;
+
+ public DocHandler(String rootName, RootHandler rootHandler) {
+ super(null, rootName);
+ this.rootHandler = rootHandler;
+ }
+
+ public void ProcessingInstruction(String target, String data) throws SAXException {
+ // Do nothing by default (except suppress warning)
+ if (false) {
+ throw new SAXException(""); //$NON-NLS-1$
+ }
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equalsIgnoreCase(elementHandled)) {
+ rootHandler.initialize(this, name, attributes);
+ xmlReader.setContentHandler(rootHandler);
+ } else {
+ this.noSubElements(name, attributes);
+ }
+ }
+
+ }
+
+ /**
+ * Abstract handler for the root element.
+ */
+ protected abstract class RootHandler extends AbstractHandler {
+
+ public RootHandler() {
+ super();
+ }
+
+ public void initialize(DocHandler document, String rootName, Attributes attributes) {
+ this.parentHandler = document;
+ this.elementHandled = rootName;
+ handleRootAttributes(attributes);
+ }
+
+ protected abstract void handleRootAttributes(Attributes attributes);
+
+ }
+
+ /**
+ * Handler for an ordered properties collection.
+ */
+ protected class PropertiesHandler extends AbstractHandler {
+
+ private OrderedProperties properties;
+
+ public PropertiesHandler(ContentHandler parentHandler, Attributes attributes) {
+ super(parentHandler, PROPERTIES_ELEMENT);
+ String size = parseOptionalAttribute(attributes, COLLECTION_SIZE_ATTRIBUTE);
+ properties = (size != null ? new OrderedProperties(new Integer(size).intValue()) : new OrderedProperties());
+ }
+
+ public OrderedProperties getProperties() {
+ return properties;
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equalsIgnoreCase(PROPERTY_ELEMENT)) {
+ new PropertyHandler(this, attributes, properties);
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+
+ }
+
+ /**
+ * Handler for a property in an ordered properties collection.
+ */
+ protected class PropertyHandler extends AbstractHandler {
+
+ public PropertyHandler(ContentHandler parentHandler, Attributes attributes, OrderedProperties properties) {
+ super(parentHandler, PROPERTY_ELEMENT);
+ String[] property = parseProperty(attributes);
+ if (isValidProperty(property)) {
+ properties.setProperty(property[0], property[1]);
+ }
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ invalidElement(name, attributes);
+ }
+
+ private String[] parseProperty(Attributes attributes) {
+ return parseRequiredAttributes(attributes, PROPERTY_NAME_ATTRIBUTE, PROPERTY_VALUE_ATTRIBUTE);
+ }
+
+ private boolean isValidProperty(String[] property) {
+ return (property.length == 2 && property[0] != null && property[1] != null);
+ }
+ }
+
+ /**
+ * Handler for an element with only cdata and no sub-elements.
+ */
+ protected class TextHandler extends AbstractHandler {
+
+ private String text = null;
+
+ private List texts = null;
+
+ // Constructor for a subclass that processes the attributes
+ public TextHandler(AbstractHandler parent, String elementName) {
+ super(parent, elementName);
+ }
+
+ // Constructor for a subclass with no attributes
+ public TextHandler(AbstractHandler parent, String elementName, Attributes attributes) {
+ super(parent, elementName);
+ parseAttributes(attributes, noAttributes, noAttributes);
+ }
+
+ public TextHandler(AbstractHandler parent, String elementName, Attributes attributes, List texts) {
+ super(parent, elementName);
+ parseAttributes(attributes, noAttributes, noAttributes);
+ this.texts = texts;
+ }
+
+ public String getText() {
+ return (text != null ? text : ""); //$NON-NLS-1$
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ invalidElement(name, attributes);
+ }
+
+ protected void processCharacters(String data) {
+ this.text = data;
+ if (texts != null) {
+ texts.add(getText());
+ }
+ }
+
+ }
+
+ /**
+ * Handler for ignoring content.
+ */
+ protected class IgnoringHandler extends AbstractHandler {
+
+ public IgnoringHandler(AbstractHandler parent) {
+ super(parent);
+ this.elementHandled = "IgnoringAll"; //$NON-NLS-1$
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ noSubElements(name, attributes);
+ }
+
+ }
+
+ // Helpers for processing instructions that include a Class and/or a Version.
+ private static final String PI_CLASS_REGEX = PI_CLASS_ATTRIBUTE + "=['\"]([\\S]*)['\"]$"; //$NON-NLS-1$
+ private static final Pattern PI_CLASS_PATTERN = Pattern.compile(PI_CLASS_REGEX);
+
+ private static final String PI_VERSION_REGEX = PI_VERSION_ATTRIBUTE + "=['\"]([\\w\\d][\\w\\d\\.]*)['\"]$"; //$NON-NLS-1$
+ private static final Pattern PI_VERSION_PATTERN = Pattern.compile(PI_VERSION_REGEX);
+
+ public String extractPIClass(String data) {
+ return PI_CLASS_PATTERN.matcher(data).replaceAll("$1"); //$NON-NLS-1$
+ }
+
+ public Version extractPIVersion(String target, String data) {
+ return checkVersion(target, PI_VERSION_ATTRIBUTE, PI_VERSION_PATTERN.matcher(data).replaceAll("$1")); //$NON-NLS-1$
+ }
+
+ public class ParserStatus extends Status implements IStatus {
+
+ int lineNumber = 0;
+ int columnNumber = 0;
+
+ public ParserStatus(int severity, int code, String message) {
+ super(severity, MultiStatus.bundleId, code, message, null);
+ }
+
+ public ParserStatus(int severity, int code, String message, int lineNumber, int columnNumber) {
+ super(severity, MultiStatus.bundleId, code, message, null);
+ setLineNumber(lineNumber);
+ setColumnNumber(columnNumber);
+ }
+
+ public int getColumnNumber() {
+ return columnNumber;
+ }
+
+ public void setColumnNumber(int columnNumber) {
+ this.columnNumber = columnNumber;
+ }
+
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ public void setLineNumber(int lineNumber) {
+ this.lineNumber = lineNumber;
+ }
+
+ }
+
+ public void error(SAXParseException ex) {
+ addError(ex);
+ }
+
+ public void fatalError(SAXParseException ex) throws SAXException {
+ addError(ex);
+ throw ex;
+ }
+
+ protected void addError(SAXParseException ex) {
+ addError(ex.getMessage());
+ }
+
+ protected String getErrorPrefix() {
+ return null;
+ }
+
+ protected String getErrorSuffix() {
+ return null;
+ }
+
+ // Log an error message and add it to the current status.
+ //
+ // TODO: should we have a flag to throw an exception on error,
+ // so parsing can be aborted?
+ // TODO: flag to produce warnings instead of errors? etc.
+ public final void addError(String msg) {
+ int line = 0;
+ int column = 0;
+ String key = msg;
+ Object[] args = new Object[] {};
+ String root = (getRootObject() == null ? "" //$NON-NLS-1$
+ : " (" + getRootObject() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (this.locator != null) {
+ String name = this.locator.getSystemId();
+ line = this.locator.getLineNumber();
+ column = this.locator.getColumnNumber();
+ if (line > 0) {
+ args = new Object[] {msg, root, name, new Integer(line), new Integer(column)};
+ if (column > 0) {
+ key = (name != null ? Messages.XMLParser_Error_At_Name_Line_Column //
+ : Messages.XMLParser_Error_At_Line_Column);
+ } else {
+ key = (name != null ? Messages.XMLParser_Error_At_Name_Line //
+ : Messages.XMLParser_Error_At_Line);
+ }
+ }
+ }
+ String errMsg = NLS.bind(key, args);
+ String prefix = getErrorPrefix();
+ String suffix = getErrorSuffix();
+ if (prefix != null) {
+ errMsg = prefix + errMsg;
+ }
+ if (suffix != null) {
+ errMsg = errMsg + suffix;
+ }
+ // TODO: support logging
+ // getLogger().warning(errMsg);
+ IStatus currStatus = new ParserStatus(IStatus.ERROR, IStatus.OK, errMsg, line, column);
+ if (this.status == null) {
+ this.status = new MultiStatus(bundleId, IStatus.OK, new IStatus[] {currStatus}, getErrorMessage(), null);
+ } else {
+ this.status.add(currStatus);
+ }
+ }
+
+ public void trace(String element, Attributes attributes) {
+ // TODO: support logging
+ // if (!getLogger().isDebugLoggable()) {
+ // return;
+ // }
+ // int indentSize = (this.stateStack != null ? this.stateStack.size() - 1 : 1);
+ // if (attributes == null) {
+ // indentSize -= 1;
+ // }
+ // char[] indent = new char[2 * indentSize];
+ // Arrays.fill(indent, ' ');
+ // StringBuffer sb = new StringBuffer();
+ // sb.append(indent);
+ // sb.append('<');
+ // if (attributes != null) {
+ // sb.append(element);
+ // toString(sb, attributes);
+ // } else {
+ // sb.append('/').append(element);
+ // }
+ // sb.append('>');
+ // getLogger().debug(sb.toString());
+ }
+
+ private static String toString(Attributes attributes) {
+ StringBuffer result = new StringBuffer();
+ toString(result, attributes);
+ return result.toString();
+ }
+
+ private static void toString(StringBuffer sb, Attributes attributes) {
+ for (int i = 0; i < attributes.getLength(); i += 1) {
+ String name = attributes.getLocalName(i);
+ String value = attributes.getValue(i).trim();
+ sb.append(' ').append(name);
+ sb.append('=').append('"');
+ sb.append(value);
+ sb.append('"');
+ }
+ }
+
+ public void error(String msg) {
+ addError(msg);
+ }
+
+ public void checkRequiredAttribute(String element, String name, Object value) {
+ if (value == null) {
+ addError(NLS.bind(Messages.XMLParser_Missing_Required_Attribute, element, name));
+ }
+ }
+
+ // Check the format of a required boolean attribute
+ public Boolean checkBoolean(String element, String attribute, String value) {
+ try {
+ return Boolean.valueOf(value);
+ } catch (IllegalArgumentException iae) {
+ invalidAttributeValue(element, attribute, value);
+ return Boolean.FALSE;
+ }
+ }
+
+ // Check the format of an optional boolean attribute
+ public Boolean checkBoolean(String element, String attribute, String value, boolean defaultValue) {
+ Boolean result = (defaultValue ? Boolean.TRUE : Boolean.FALSE);
+ if (value != null) {
+ try {
+ return Boolean.valueOf(value);
+ } catch (IllegalArgumentException iae) {
+ invalidAttributeValue(element, attribute, value);
+ }
+ }
+ return result;
+ }
+
+ public Version checkVersion(String element, String attribute, String value) {
+ try {
+ return new Version(value);
+ } catch (IllegalArgumentException iae) {
+ invalidAttributeValue(element, attribute, value);
+ }
+ return Version.emptyVersion;
+ }
+
+ public VersionRange checkVersionRange(String element, String attribute, String value) {
+ try {
+ return new VersionRange(value);
+ } catch (IllegalArgumentException iae) {
+ invalidAttributeValue(element, attribute, value);
+ }
+ return VersionRange.emptyRange;
+ }
+
+ public void unexpectedAttribute(String element, String attribute, String value) {
+ addError(NLS.bind(Messages.XMLParser_Unexpected_Attribute, new Object[] {element, attribute, value}));
+ }
+
+ public void invalidAttributeValue(String element, String attribute, String value) {
+ addError(NLS.bind(Messages.XMLParser_Illegal_Value_For_Attribute, new Object[] {attribute, element, value}));
+ }
+
+ public void unexpectedElement(AbstractHandler handler, String element, Attributes attributes) {
+ addError(NLS.bind(Messages.XMLParser_Unexpected_Element, new Object[] {handler.getName(), element, toString(attributes)}));
+ }
+
+ public void duplicateElement(AbstractHandler handler, String element, Attributes attributes) {
+ addError(NLS.bind(Messages.XMLParser_Duplicate_Element, new Object[] {handler.getName(), element, toString(attributes)}));
+ }
+
+ public void unexpectedCharacterData(AbstractHandler handler, String cdata) {
+ addError(NLS.bind(Messages.XMLParser_Unexpected_Character_Data, handler.getName(), cdata.trim()));
+ }
+
+ /**
+ * Find the index of the first occurrence of object in array, or -1.
+ * Use Arrays.binarySearch if array is big and sorted.
+ */
+ protected static int indexOf(String[] array, String value) {
+ for (int i = 0; i < array.length; i += 1) {
+ if (value == null ? array[i] == null : value.equals(array[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ // public class BadStateError extends AssertionError {
+ // private static final long serialVersionUID = 1L; // not serialized
+ //
+ // public BadStateError() {
+ // super("unexpected state" + //$NON-NLS-1$
+ // (XMLParser.this.stateStack != null ? ": " + XMLParser.this.stateStack //$NON-NLS-1$
+ // : "")); //$NON-NLS-1$
+ // }
+ //
+ // public BadStateError(String element) {
+ // super("unexpected state for " + element + //$NON-NLS-1$
+ // (XMLParser.this.stateStack != null ? ": " + XMLParser.this.stateStack //$NON-NLS-1$
+ // : "")); //$NON-NLS-1$
+ // }
+ // }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLUtils.java b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLUtils.java
new file mode 100644
index 000000000..ed72bf65c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLUtils.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * 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 Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.p2.core.helpers;
+
+public class XMLUtils {
+
+ public static String escape(String txt) {
+ // Traverse the string from right to left as the length
+ // may increase as result of processing
+ for (int i = txt.length() - 1; i >= 0; i -= 1) {
+ String replace;
+ switch (txt.charAt(i)) {
+ case '<' :
+ replace = "&lt;"; //$NON-NLS-1$
+ break;
+ case '>' :
+ replace = "&gt;"; //$NON-NLS-1$
+ break;
+ case '"' :
+ replace = "&quot;"; //$NON-NLS-1$
+ break;
+ case '\'' :
+ replace = "&apos;"; //$NON-NLS-1$
+ break;
+ case '&' :
+ replace = "&amp;"; //$NON-NLS-1$
+ break;
+ default :
+ continue;
+ }
+ txt = txt.substring(0, i) + replace + txt.substring(i + 1);
+ }
+ return txt;
+ }
+
+ // A string constant for no indentation.
+ protected static final String NO_INDENT = ""; //$NON-NLS-1$
+
+ // A constant for maximum line length before break and indent
+ protected static final int MAX_LINE = 72;
+
+ /*
+ * Construct a string for a simple XML element
+ * with no text or child elements, just attributes
+ * expressed as name/value pairs.
+ *
+ * e.g <elemName attr1='value1' attr2='value2'/>
+ */
+ public static String simpleElement(String elementName, String[] attrNameValuePairs) {
+ StringBuffer buffer = new StringBuffer();
+ simpleElement(elementName, attrNameValuePairs, buffer, NO_INDENT);
+
+ return buffer.toString();
+ }
+
+ /*
+ * Write a string for a simple XML element
+ * with no text or child elements, just attributes
+ * expressed as name/value pairs, into the given
+ * string buffer using the given indentation.
+ *
+ * e.g. <elemName attr1='value1' attr2='value2'/>
+ */
+ public static void simpleElement(String elementName, String[] attrNameValuePairs, StringBuffer buffer, String indent) {
+ element(elementName, attrNameValuePairs, buffer, indent, "/>"); //$NON-NLS-1$
+ }
+
+ /*
+ * Write a string for an open XML element, including
+ * the attributes expressed as name/value pairs,
+ * into the given string buffer using the given indentation.
+ *
+ * The caller is responsible for adding any child elements
+ * and closing the element.
+ *
+ * Eg. <elemName attr1='value1' attr2='value2'>
+ */
+ public static void openElement(String elementName, String[] attrNameValuePairs, StringBuffer buffer, String indent) {
+ element(elementName, attrNameValuePairs, buffer, indent, ">"); //$NON-NLS-1$
+ }
+
+ /*
+ * Write a string for an unterminated XML element, including
+ * the attributes expressed as name/value pairs,
+ * into the given string buffer using the given indentation.
+ *
+ * The caller is responsible for terminating the element.
+ *
+ * e.g. <elemName attr1='value1' attr2='value2'
+ */
+ public static void unterminatedElement(String elementName, String[] attrNameValuePairs, StringBuffer buffer, String indent) {
+ buffer.append(indent).append('<').append(elementName);
+
+ String attrPrefix = " "; //$NON-NLS-1$
+ int totalLen = buffer.length() + 1;
+ for (int i = 0; i < attrNameValuePairs.length; i++) {
+ String next = attrNameValuePairs[i];
+ if (next != null) {
+ totalLen += next.length() + 2;
+ if (totalLen >= MAX_LINE) {
+ attrPrefix = '\n' + indent + " "; //$NON-NLS-1$
+ break;
+ }
+ }
+ }
+
+ for (int i = 0; i < attrNameValuePairs.length;) {
+ String name = attrNameValuePairs[i++];
+ if (name.length() > 0) {
+ String value = (i < attrNameValuePairs.length ? attrNameValuePairs[i++] : null);
+ if (value != null) {
+ buffer.append(attrPrefix).append(name);
+ buffer.append("='").append(escape(value)).append('\''); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ /*
+ * Fill the string buffer for a XML element, including
+ * the attributes expressed as name/value pairs, and
+ * terminate with the given termination string.
+ *
+ * e.g. <elemName attr1='value1' attr2='value2'>
+ * or <elemName attr1='value1' attr2='value2'>
+ */
+ private static void element(String elementName, String[] attrNameValuePairs, StringBuffer buffer, String indent, String termination) {
+ unterminatedElement(elementName, attrNameValuePairs, buffer, indent);
+ buffer.append(termination);
+ }
+
+ private XMLUtils() {
+ // Private constructor to ensure no instances are created.
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLWriter.java b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLWriter.java
new file mode 100644
index 000000000..e5a1fc47d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/XMLWriter.java
@@ -0,0 +1,348 @@
+/*******************************************************************************
+ * 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 Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.p2.core.helpers;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.Pattern;
+import org.osgi.framework.Version;
+
+public class XMLWriter implements XMLConstants {
+
+ // Miscellaneous
+ public static final String EMPTY_ATTR = ""; //$NON-NLS-1$
+
+ public static class ProcessingInstruction {
+
+ private String target;
+ private String[] data;
+
+ // The standard UTF-8 processing instruction
+ public static final String XML_UTF8 = "<?xml version='1.0' encoding='UTF-8'?>"; //$NON-NLS-1$
+
+ public ProcessingInstruction(String target, String data) {
+ this.target = target;
+ this.data = new String[] {data};
+ }
+
+ public ProcessingInstruction(String target) {
+ this.target = target;
+ this.data = new String[0];
+ }
+
+ public ProcessingInstruction(String target, String[] data) {
+ this.target = target;
+ this.data = data;
+ }
+
+ public ProcessingInstruction(String target, String[] attrs, String[] values) {
+ // Lengths of attributes and values must be the same
+ this.target = target;
+ this.data = new String[attrs.length];
+ for (int i = 0; i < attrs.length; i++) {
+ data[i] = attributeImage(attrs[i], values[i]);
+ }
+ }
+
+ public static ProcessingInstruction makeClassVersionInstruction(String target, Class clazz, Version version) {
+ return new ProcessingInstruction(target, new String[] {PI_CLASS_ATTRIBUTE, PI_VERSION_ATTRIBUTE}, new String[] {clazz.getName(), version.toString()});
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer("<?"); //$NON-NLS-1$
+ sb.append(this.target).append(' ');
+ for (int i = 0; i < data.length; i++) {
+ sb.append(this.data[i]);
+ if (i < data.length - 1) {
+ sb.append(' ');
+ }
+ }
+ sb.append("?>"); //$NON-NLS-1$
+ return sb.toString();
+ }
+ }
+
+ private Stack elements; // XML elements that have not yet been closed
+ private boolean open; // Can attributes be added to the current element?
+ private String indent; // used for each level of indentation
+
+ private PrintWriter pw;
+
+ private XMLWriter(OutputStream output, boolean writeXMLProcessingInstruction) throws UnsupportedEncodingException {
+ this.pw = new PrintWriter(new OutputStreamWriter(output, "UTF8"), true); //$NON-NLS-1$
+ if (writeXMLProcessingInstruction) {
+ println(ProcessingInstruction.XML_UTF8);
+ }
+ this.elements = new Stack();
+ this.open = false;
+ this.indent = " "; //$NON-NLS-1$
+ }
+
+ public XMLWriter(OutputStream output, ProcessingInstruction piElement, boolean writeXMLProcessingInstruction) throws UnsupportedEncodingException {
+ this(output, new ProcessingInstruction[] {piElement}, writeXMLProcessingInstruction);
+ }
+
+ public XMLWriter(OutputStream output, ProcessingInstruction piElement) throws UnsupportedEncodingException {
+ this(output, new ProcessingInstruction[] {piElement}, true /* writeXMLProcessingInstruction */);
+ }
+
+ public XMLWriter(OutputStream output, ProcessingInstruction[] piElements, boolean writeXMLProcessingInstruction) throws UnsupportedEncodingException {
+ this(output, writeXMLProcessingInstruction);
+ if (piElements != null) {
+ for (int i = 0; i < piElements.length; i++) {
+ println(piElements[i].toString());
+ }
+ }
+ }
+
+ public XMLWriter(OutputStream output, ProcessingInstruction[] piElements) throws UnsupportedEncodingException {
+ this(output, piElements, /* writeXMLProcessingInstruction */
+ true);
+ }
+
+ // String used for each level of indentation; default is two spaces.
+ public void setIndent(String indent) {
+ this.indent = indent;
+ }
+
+ // start a new element
+ public void start(String name) {
+ if (this.open) {
+ println('>');
+ }
+ indent();
+ print('<');
+ print(name);
+ this.elements.push(name);
+ this.open = true;
+ }
+
+ // end the most recent element with this name
+ public void end(String name) {
+ if (this.elements.empty()) {
+ throw new EndWithoutStartError();
+ }
+ int index = this.elements.search(name);
+ if (index == -1) {
+ throw new EndWithoutStartError(name);
+ }
+ for (int i = 0; i < index; i += 1) {
+ end();
+ }
+ }
+
+ // end the current element
+ public void end() {
+ if (this.elements.empty()) {
+ throw new EndWithoutStartError();
+ }
+ String name = (String) this.elements.pop();
+ if (this.open) {
+ println("/>"); //$NON-NLS-1$
+ } else {
+ printlnIndented("</" + name + '>', false); //$NON-NLS-1$
+ }
+ this.open = false;
+ }
+
+ // write a boolean attribute if it doesn't have the default value
+ public void attribute(String name, boolean value, boolean defaultValue) {
+ if (value != defaultValue) {
+ attribute(name, value);
+ }
+ }
+
+ public void attribute(String name, boolean value) {
+ attribute(name, Boolean.toString(value));
+ }
+
+ public void attribute(String name, int value) {
+ attribute(name, Integer.toString(value));
+ }
+
+ public void attributeOptional(String name, String value) {
+ if (value.length() > 0) {
+ attribute(name, value);
+ }
+ }
+
+ public void attribute(String name, Object value) {
+ if (!this.open) {
+ throw new AttributeAfterNestedContentError();
+ }
+ if (value == null) {
+ return; // optional attribute with no value
+ }
+ print(' ');
+ print(name);
+ print("='"); //$NON-NLS-1$
+ print(XMLUtils.escape(value.toString()));
+ print('\'');
+ }
+
+ public void cdata(String data) {
+ cdata(data, true);
+ }
+
+ public void cdata(String data, boolean escape) {
+ if (this.open) {
+ println('>');
+ this.open = false;
+ }
+ if (data != null) {
+ printlnIndented(data, escape);
+ }
+ }
+
+ public void cdataLines(String data, boolean escape) {
+ if (this.open) {
+ println('>');
+ this.open = false;
+ }
+ if (data.indexOf('\n') == -1) {
+ // simple case: one line
+ printlnIndented(data, escape);
+ } else {
+ String[] lines = Pattern.compile("\\s*\\n").split(data, 0); //$NON-NLS-1$
+ for (int i = 0; i < lines.length; i += 1) {
+ printlnIndented(lines[i].trim(), escape);
+ }
+ }
+ }
+
+ public void flush() {
+ while (!this.elements.empty()) {
+ try {
+ end();
+ } catch (EndWithoutStartError e) {
+ // can't happen
+ }
+ }
+ this.pw.flush();
+ }
+
+ public void close() {
+ flush();
+ this.pw.close();
+ }
+
+ public void writeProperties(Map properties) {
+ writeProperties(PROPERTIES_ELEMENT, properties);
+ }
+
+ public void writeProperties(String propertiesElement, Map properties) {
+ if (properties != null && properties.size() > 0) {
+ start(propertiesElement);
+ attribute(COLLECTION_SIZE_ATTRIBUTE, properties.size());
+ for (Iterator iter = properties.keySet().iterator(); iter.hasNext();) {
+ String name = (String) iter.next();
+ writeProperty(name, (String) properties.get(name));
+ }
+ end(propertiesElement);
+ }
+ }
+
+ // Support writing properties with an auxiliary map
+ // of keys to localized values
+ public void writeProperties(Map properties, Map localizedValues) {
+ writeProperties(PROPERTIES_ELEMENT, properties, localizedValues);
+ }
+
+ // Support writing properties with an auxiliary map
+ // of keys to localized values
+ public void writeProperties(String propertiesElement, Map properties, Map localizedValues) {
+ if (properties != null && properties.size() > 0 && localizedValues != null) {
+ start(propertiesElement);
+ for (Iterator I = properties.entrySet().iterator(); I.hasNext();) {
+ Map.Entry property = (Map.Entry) I.next();
+ String key = (String) property.getKey();
+ String val = (String) property.getValue();
+ if (localizedValues.containsKey(key)) {
+ val = (String) localizedValues.get(key);
+ }
+ writeProperty(key, val);
+ }
+ end(propertiesElement);
+ }
+ }
+
+ public void writeProperty(String name, String value) {
+ start(PROPERTY_ELEMENT);
+ attribute(PROPERTY_NAME_ATTRIBUTE, name);
+ attribute(PROPERTY_VALUE_ATTRIBUTE, value);
+ end();
+ }
+
+ protected static String attributeImage(String name, String value) {
+ if (value == null) {
+ return EMPTY_ATTR; // optional attribute with no value
+ }
+ return name + "='" + XMLUtils.escape(value) + '\''; //$NON-NLS-1$
+ }
+
+ private void println(char c) {
+ this.pw.println(c);
+ }
+
+ private void println(String s) {
+ this.pw.println(s);
+ }
+
+ private void println() {
+ this.pw.println();
+ }
+
+ private void print(char c) {
+ this.pw.print(c);
+ }
+
+ private void print(String s) {
+ this.pw.print(s);
+ }
+
+ private void printlnIndented(String s, boolean escape) {
+ if (s.length() == 0) {
+ println();
+ } else {
+ indent();
+ println(escape ? XMLUtils.escape(s) : s);
+ }
+ }
+
+ private void indent() {
+ for (int i = this.elements.size(); i > 0; i -= 1) {
+ print(this.indent);
+ }
+ }
+
+ public static class AttributeAfterNestedContentError extends Error {
+ private static final long serialVersionUID = 1L; // not serialized
+ }
+
+ public static class EndWithoutStartError extends Error {
+ private static final long serialVersionUID = 1L; // not serialized
+ private String name;
+
+ public EndWithoutStartError() {
+ super();
+ }
+
+ public EndWithoutStartError(String name) {
+ super();
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/messages.properties b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/messages.properties
index a5294426c..0f58a17af 100644
--- a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/messages.properties
+++ b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/p2/core/helpers/messages.properties
@@ -12,4 +12,17 @@
Util_Invalid_Zip_File_Format=Invalid zip file format
Util_Error_Unzipping=Error unzipping {0}: {1}
+# All these errors are bound to 5 args: 0-msg, 1-root, 2-name, 3-line, 4-column
+XMLParser_Error_At_Line=Error at line {3}{1}: {0}
+XMLParser_Error_At_Line_Column=Error at line {3}, column {4}{1}: {0}
+XMLParser_Error_At_Name_Line=Error in {2} at line {3}: {0}
+XMLParser_Error_At_Name_Line_Column=Error in {2} at line {3}, column {4}: {0}
+XMLParser_No_SAX_Parser=Unable to acquire a SAX parser service.
+XMLParser_Missing_Required_Attribute=Missing required attribute in "{0}": {1}
+XMLParser_Unexpected_Attribute=Unexpected attribute for element "{0}": {1}="{2}"
+XMLParser_Illegal_Value_For_Attribute=Illegal value for attribute "{0}" of element "{1}": {2}
+XMLParser_Unexpected_Element=Unexpected element in element "{0}": <{1}{2}>
+XMLParser_Duplicate_Element=Duplicate singleton element in element "{0}": <{1}{2}>
+XMLParser_Unexpected_Character_Data=Unexpected character data in element "{0}": {1}
+XMLParser_Element_Not_Allowed=Element "{0}" is not allowed within element "{1}"
diff --git a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/spi/p2/core/repository/AbstractRepository.java b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/spi/p2/core/repository/AbstractRepository.java
index 153abc62d..0f9a9b616 100644
--- a/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/spi/p2/core/repository/AbstractRepository.java
+++ b/bundles/org.eclipse.equinox.p2.core/src/org/eclipse/equinox/spi/p2/core/repository/AbstractRepository.java
@@ -31,7 +31,6 @@ public abstract class AbstractRepository extends PlatformObject implements IRepo
protected String version;
protected String description;
protected String provider;
- // TODO make sure that this is transiaent. NO point in storing the location in the repo itself.
protected transient URL location;
protected OrderedProperties properties = new OrderedProperties();
diff --git a/bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator CDT bad.launch b/bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator CDT bad.launch
new file mode 100644
index 000000000..c2acdb4f9
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator CDT bad.launch
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.pde.ui.EquinoxLauncher">
+<booleanAttribute key="automaticAdd" value="false"/>
+<booleanAttribute key="automaticValidate" value="false"/>
+<stringAttribute key="bootstrap" value=""/>
+<stringAttribute key="checked" value="[NONE]"/>
+<booleanAttribute key="clearConfig" value="false"/>
+<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/Metadata Generator CDT"/>
+<booleanAttribute key="default_auto_start" value="false"/>
+<intAttribute key="default_start_level" value="4"/>
+<booleanAttribute key="includeOptional" value="false"/>
+<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-console&#13;&#10;-consolelog&#13;&#10;-application org.eclipse.equinox.p2.metadata.generator.EclipseGenerator&#13;&#10;-metadataRepository file:C:/Ap2/servers/CDTmetadataRepository/&#13;&#10;-artifactRepository file:C:/Ap2/servers/CDTartifactRepository/&#13;&#10;-source C:/eclipse/CDT4.0 &#13;&#10;-root cdt&#13;&#10;-rootVersion 4.0.0&#13;&#10;-flavor tooling&#13;&#10;-publishArtifacts&#13;&#10;-append"/>
+<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
+<stringAttribute key="target_bundles" value="org.eclipse.core.contenttype@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:default,org.eclipse.core.runtime.compatibility.registry@default:default,org.eclipse.equinox.app@default:true,org.eclipse.equinox.common@default:default,org.eclipse.equinox.launcher@default:default,org.eclipse.equinox.launcher.win32.win32.x86@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.registry@default:default,org.eclipse.osgi@:,org.eclipse.osgi.services@default:default,org.eclipse.update.configurator@default:default"/>
+<booleanAttribute key="tracing" value="false"/>
+<booleanAttribute key="useDefaultConfigArea" value="true"/>
+<stringAttribute key="vminstall" value="JRE1.4.2"/>
+<stringAttribute key="workspace_bundles" value="com.thoughtworks.xstream@default:default,org.eclipse.ecf@default:default,org.eclipse.ecf.filetransfer@default:default,org.eclipse.ecf.identity@default:default,org.eclipse.equinox.frameworkadmin@default:default,org.eclipse.equinox.frameworkadmin.equinox@default:true,org.eclipse.equinox.p2.artifact.repository@default:default,org.eclipse.equinox.p2.core@default:default,org.eclipse.equinox.p2.download@default:default,org.eclipse.equinox.p2.engine@default:default,org.eclipse.equinox.p2.metadata@default:default,org.eclipse.equinox.p2.metadata.generator@default:default,org.eclipse.equinox.p2.metadata.repository@default:default"/>
+</launchConfiguration>
diff --git a/bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator CDT.launch b/bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator CDT.launch
index 903a0f163..6ec5e0623 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator CDT.launch
+++ b/bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator CDT.launch
@@ -1,21 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.EquinoxLauncher">
+<booleanAttribute key="append.args" value="true"/>
<booleanAttribute key="automaticAdd" value="false"/>
<booleanAttribute key="automaticValidate" value="false"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
-<booleanAttribute key="clearConfig" value="true"/>
-<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/Metadata Generator CDT"/>
+<booleanAttribute key="clearConfig" value="false"/>
+<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/Metadata Generator CDT2"/>
<booleanAttribute key="default_auto_start" value="false"/>
<intAttribute key="default_start_level" value="4"/>
-<booleanAttribute key="includeOptional" value="true"/>
+<booleanAttribute key="includeOptional" value="false"/>
<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-console&#13;&#10;-consolelog &#13;&#10;-application org.eclipse.equinox.p2.metadata.generator.EclipseGenerator&#13;&#10;-metadataRepository file:c:/temp/equinox.p2/servers/CDTmetadataRepository/ &#13;&#10;-artifactRepository file:c:/temp/equinox.p2/servers/CDTartifactRepository/ &#13;&#10;-source c:/eclipse/CDT4.0 &#13;&#10;-root cdt&#13;&#10;-flavor tooling&#13;&#10;-publishArtifacts"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-console&#13;&#10;-consolelog&#13;&#10;-application org.eclipse.equinox.p2.metadata.generator.EclipseGenerator&#13;&#10;-metadataRepository file:C:/Ap2/servers/CDTmetadataRepository/&#13;&#10;-artifactRepository file:C:/Ap2/servers/CDTartifactRepository/&#13;&#10;-source C:/eclipse/CDT4.0 &#13;&#10;-root cdt&#13;&#10;-rootVersion 4.0.0&#13;&#10;-flavor tooling&#13;&#10;-publishArtifacts&#13;&#10;-append"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Declipse.p2.data.area=c:/temp/equinox.p2/agent/ &#13;&#10;-Declipse.p2.metadataRepository=file:c:/temp/equinox.p2/servers/CDTmetadataRepository/ &#13;&#10;-Declipse.p2.artifactRepository=file:c:/temp/equinox.p2/servers/artifactRepository/&#13;&#10;-Declipse.ignoreApp=false&#13;&#10;-Declipse.application.registerDescriptors=true &#13;&#10;-Declipse.application=org.eclipse.equinox.p2.metadata.generator.EclipseGenerator&#13;&#10;-Declipse.p2.metadataGenerator.eclipseBase=c:/eclipse/CDT4.0/&#13;&#10;-Declipse.p2.rootIUId=cdt &#13;&#10;-Declipse.p2.configurationFlavor=tooling&#13;&#10;-Declipse.p2.appendToRepo=true &#13;&#10;-Declipse.p2.generateArtifacts=true"/>
-<stringAttribute key="target_bundles" value="org.eclipse.core.jobs@default:default,org.eclipse.equinox.app@default:true,org.eclipse.equinox.common@default:default,org.eclipse.equinox.launcher@default:default,org.eclipse.equinox.registry@default:default,org.eclipse.osgi@:,org.eclipse.osgi.services@default:default"/>
+<stringAttribute key="pde.version" value="3.3"/>
+<stringAttribute key="target_bundles" value="org.eclipse.core.contenttype@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:default,org.eclipse.core.runtime.compatibility.registry@default:default,org.eclipse.equinox.app@default:true,org.eclipse.equinox.common@default:default,org.eclipse.equinox.launcher@default:default,org.eclipse.equinox.launcher.win32.win32.x86@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.registry@default:default,org.eclipse.osgi@:,org.eclipse.osgi.services@default:default,org.eclipse.update.configurator@default:default"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="true"/>
-<stringAttribute key="vminstall" value="jdk"/>
+<stringAttribute key="vminstall" value="JRE1.4.2"/>
<stringAttribute key="workspace_bundles" value="com.thoughtworks.xstream@default:default,org.eclipse.ecf@default:default,org.eclipse.ecf.filetransfer@default:default,org.eclipse.ecf.identity@default:default,org.eclipse.equinox.frameworkadmin@default:default,org.eclipse.equinox.frameworkadmin.equinox@default:true,org.eclipse.equinox.p2.artifact.repository@default:default,org.eclipse.equinox.p2.core@default:default,org.eclipse.equinox.p2.download@default:default,org.eclipse.equinox.p2.engine@default:default,org.eclipse.equinox.p2.metadata@default:default,org.eclipse.equinox.p2.metadata.generator@default:default,org.eclipse.equinox.p2.metadata.repository@default:default"/>
</launchConfiguration>
diff --git a/bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator SDK.launch b/bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator SDK.launch
index 0a6ef35fc..c5ec056d1 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator SDK.launch
+++ b/bundles/org.eclipse.equinox.p2.metadata.generator/Metadata Generator SDK.launch
@@ -11,12 +11,12 @@
<intAttribute key="default_start_level" value="4"/>
<booleanAttribute key="includeOptional" value="false"/>
<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-console &#13;&#10;-consolelog &#13;&#10;-application org.eclipse.equinox.p2.metadata.generator.EclipseGenerator&#13;&#10;-metadataRepository file:d:/tmp/equinox.p2/servers/metadataRepository/ &#13;&#10;-artifactRepository file:d:/tmp/equinox.p2/servers/artifactRepository/ &#13;&#10;-source d:/3.3/eclipse&#13;&#10;-root sdk&#13;&#10;-rootVersion 3.3.0&#13;&#10;-flavor tooling&#13;&#10;-publishArtifacts&#13;&#10;-append"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-console &#13;&#10;-consolelog&#13;&#10;-application org.eclipse.equinox.p2.metadata.generator.EclipseGenerator&#13;&#10;-metadataRepository file:C:/Ap2/servers2/metadataRepository/ &#13;&#10;-artifactRepository file:C:/Ap2/servers2/artifactRepository/ &#13;&#10;-source C:/eclipse/3.3/eclipse&#13;&#10;-root sdk&#13;&#10;-rootVersion 3.3.0&#13;&#10;-flavor tooling&#13;&#10;-publishArtifacts&#13;&#10;-append"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="pde.version" value="3.3"/>
-<stringAttribute key="target_bundles" value="org.eclipse.core.contenttype@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:default,org.eclipse.core.runtime.compatibility.registry@default:default,org.eclipse.equinox.app@default:true,org.eclipse.equinox.common@default:default,org.eclipse.equinox.launcher@default:default,org.eclipse.equinox.launcher.win32.win32.x86@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.registry@default:default,org.eclipse.osgi@:,org.eclipse.osgi.services@default:default,org.eclipse.update.configurator@default:default"/>
+<stringAttribute key="target_bundles" value="com.ibm.icu@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:default,org.eclipse.core.runtime.compatibility.registry@default:default,org.eclipse.equinox.app@default:true,org.eclipse.equinox.common@default:default,org.eclipse.equinox.launcher@default:default,org.eclipse.equinox.launcher.win32.win32.x86@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.registry@default:default,org.eclipse.osgi@:,org.eclipse.osgi.services@default:default,org.eclipse.update.configurator@default:default"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="true"/>
-<stringAttribute key="vminstall" value="jre1.6.0"/>
-<stringAttribute key="workspace_bundles" value="com.thoughtworks.xstream@default:default,org.eclipse.ecf@default:default,org.eclipse.ecf.filetransfer@default:default,org.eclipse.ecf.identity@default:default,org.eclipse.equinox.frameworkadmin@default:default,org.eclipse.equinox.frameworkadmin.equinox@default:true,org.eclipse.equinox.p2.artifact.repository@default:default,org.eclipse.equinox.p2.core@default:default,org.eclipse.equinox.p2.download@default:default,org.eclipse.equinox.p2.engine@default:default,org.eclipse.equinox.p2.metadata@default:default,org.eclipse.equinox.p2.metadata.generator@default:default,org.eclipse.equinox.p2.metadata.repository@default:default"/>
+<stringAttribute key="vminstall" value="JRE1.4.2"/>
+<stringAttribute key="workspace_bundles" value="com.thoughtworks.xstream@default:default,org.apache.xerces@default:default,org.apache.xml.resolver@default:default,org.eclipse.ecf@default:default,org.eclipse.ecf.filetransfer@default:default,org.eclipse.ecf.identity@default:default,org.eclipse.equinox.frameworkadmin@default:default,org.eclipse.equinox.frameworkadmin.equinox@default:true,org.eclipse.equinox.p2.artifact.repository@default:default,org.eclipse.equinox.p2.core@default:default,org.eclipse.equinox.p2.download@default:default,org.eclipse.equinox.p2.engine@default:default,org.eclipse.equinox.p2.metadata@default:default,org.eclipse.equinox.p2.metadata.generator@default:default,org.eclipse.equinox.p2.metadata.repository@default:default"/>
</launchConfiguration>
diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/.classpath b/bundles/org.eclipse.equinox.p2.metadata.repository/.classpath
index 7cdeb7319..ce7393340 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.repository/.classpath
+++ b/bundles/org.eclipse.equinox.p2.metadata.repository/.classpath
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/CDC-1.1%Foundation-1.1"/>
+ <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/bundles/org.eclipse.equinox.p2.metadata.repository/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.metadata.repository/META-INF/MANIFEST.MF
index 9d141f2ae..218d5a1bc 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.repository/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.p2.metadata.repository/META-INF/MANIFEST.MF
@@ -10,6 +10,7 @@ Export-Package: org.eclipse.equinox.internal.p2.metadata.repository;x-friends:="
org.eclipse.equinox.spi.p2.metadata.repository
Import-Package: com.thoughtworks.xstream,
org.eclipse.core.runtime.preferences,
+ org.eclipse.equinox.internal.p2.metadata,
org.eclipse.equinox.p2.core.eventbus,
org.eclipse.equinox.p2.core.helpers,
org.eclipse.equinox.p2.core.location,
@@ -22,7 +23,8 @@ Import-Package: com.thoughtworks.xstream,
org.eclipse.osgi.service.resolver;version="1.1.0",
org.eclipse.osgi.util;version="1.1.0",
org.osgi.framework;version="1.3.0",
- org.osgi.service.prefs;version="1.1.0"
+ org.osgi.service.prefs;version="1.1.0",
+ org.xml.sax
Bundle-Activator: org.eclipse.equinox.internal.p2.metadata.repository.Activator
Eclipse-LazyStart: true
Bundle-RequiredExecutionEnvironment: CDC-1.1/Foundation-1.1,
diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/LocalMetadataRepository.java b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/LocalMetadataRepository.java
index 5a9ebaf4d..1405dcc75 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/LocalMetadataRepository.java
+++ b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/LocalMetadataRepository.java
@@ -35,7 +35,7 @@ public class LocalMetadataRepository extends AbstractMetadataRepository {
static final private Integer REPOSITORY_VERSION = new Integer(1);
static final private String CONTENT_FILENAME = "content.xml"; //$NON-NLS-1$
- protected HashSet units = new HashSet();
+ protected HashSet units = new LinkedHashSet();
public static File getActualLocation(URL location) {
String spec = location.getFile();
@@ -48,12 +48,20 @@ public class LocalMetadataRepository extends AbstractMetadataRepository {
return new File(spec);
}
+ public LocalMetadataRepository() {
+ super();
+ }
+
public LocalMetadataRepository(URL location, String name) throws RepositoryCreationException {
super(name == null ? (location != null ? location.toExternalForm() : "") : name, REPOSITORY_TYPE, REPOSITORY_VERSION.toString(), location, null, null);
if (!location.getProtocol().equals("file")) //$NON-NLS-1$
throw new IllegalArgumentException("Invalid local repository location: " + location);
}
+ protected LocalMetadataRepository(String name, String type, String version, URL location, String description, String provider) {
+ super(name, type, version, location, description, provider);
+ }
+
public IInstallableUnit[] getInstallableUnits(IProgressMonitor monitor) {
if (monitor == null) {
monitor = new NullProgressMonitor();
@@ -124,4 +132,21 @@ public class LocalMetadataRepository extends AbstractMetadataRepository {
public boolean isModifiable() {
return true;
}
+
+ // Get a non-modifiable collection of the installable units
+ // from the repository.
+ public Set getInstallableUnits() {
+ return Collections.unmodifiableSet(units);
+ }
+
+ public void initialize(RepositoryState state) {
+ this.name = state.Name;
+ this.type = state.Type;
+ this.version = state.Version.toString();
+ this.provider = state.Provider;
+ this.description = state.Description;
+ this.location = state.Location;
+ this.properties = state.Properties;
+ this.units.addAll(Arrays.asList(state.Units));
+ }
}
diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/Messages.java b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/Messages.java
index 7d2647a9b..942db82c3 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/Messages.java
+++ b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/Messages.java
@@ -24,4 +24,8 @@ public class Messages extends NLS {
public static String REPO_LOADING;
public static String REPOMGR_ADDING_REPO;
+
+ public static String MetadataRepositoryIO_Parser_Has_Incompatible_Version;
+ public static String MetadataRepositoryIO_Parser_Error_Parsing_Repository;
+
}
diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/MetadataRepositoryIO.java b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/MetadataRepositoryIO.java
index b05dec4e1..2e951e17d 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/MetadataRepositoryIO.java
+++ b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/MetadataRepositoryIO.java
@@ -13,8 +13,22 @@ package org.eclipse.equinox.internal.p2.metadata.repository;
import com.thoughtworks.xstream.XStream;
import java.io.*;
+import java.util.*;
+import javax.xml.parsers.ParserConfigurationException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.equinox.internal.p2.metadata.ArtifactKey;
+import org.eclipse.equinox.p2.core.helpers.*;
import org.eclipse.equinox.p2.core.repository.RepositoryCreationException;
+import org.eclipse.equinox.p2.metadata.*;
import org.eclipse.equinox.p2.metadata.repository.IMetadataRepository;
+import org.eclipse.equinox.spi.p2.metadata.repository.AbstractMetadataRepository;
+import org.eclipse.equinox.spi.p2.metadata.repository.AbstractMetadataRepository.RepositoryState;
+import org.eclipse.osgi.service.resolver.VersionRange;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Version;
+import org.xml.sax.*;
/**
* This class reads and writes provisioning metadata.
@@ -26,6 +40,8 @@ class MetadataRepositoryIO {
* Reads metadata from the given stream, and returns the contained array
* of abstract metadata repositories.
* This method performs buffering, and closes the stream when finished.
+ *
+ * @deprecated
*/
public static IMetadataRepository read(InputStream input) throws RepositoryCreationException {
XStream stream = new XStream();
@@ -43,6 +59,9 @@ class MetadataRepositoryIO {
}
}
+ /**
+ * @deprecated
+ */
public static void write(IMetadataRepository repository, OutputStream output) {
XStream stream = new XStream();
OutputStream bufferedOutput = null;
@@ -62,4 +81,880 @@ class MetadataRepositoryIO {
e.printStackTrace();
}
}
+
+ public void writeNew(IMetadataRepository repository, OutputStream output) {
+ OutputStream bufferedOutput = null;
+ try {
+ try {
+ bufferedOutput = new BufferedOutputStream(output);
+ Writer repositoryWriter = new Writer(bufferedOutput, repository.getClass());
+ repositoryWriter.write(repository);
+ } finally {
+ if (bufferedOutput != null) {
+ bufferedOutput.close();
+ }
+ }
+ } catch (IOException ioe) {
+ // TODO shouldn't this throw a core exception?
+ ioe.printStackTrace();
+ }
+ }
+
+ /**
+ * Reads metadata from the given stream, and returns the contained array
+ * of abstract metadata repositories.
+ * This method performs buffering, and closes the stream when finished.
+ */
+ public IMetadataRepository readNew(InputStream input) throws RepositoryCreationException {
+ BufferedInputStream bufferedInput = null;
+ try {
+ try {
+ bufferedInput = new BufferedInputStream(input);
+
+ Parser repositoryParser = new Parser(Activator.getContext(), Activator.ID);
+ repositoryParser.parse(input);
+ if (repositoryParser.isValidXML()) {
+ throw new RepositoryCreationException(new CoreException(repositoryParser.getStatus()));
+ }
+ IMetadataRepository theRepository = repositoryParser.getRepository();
+ // TODO: temporary - try write after read for comparison:
+ // see note below about call to writeInstallableUnits(...)
+ writeNew(theRepository, new FileOutputStream(new File("C:/Ap2/servers2/metadataRepository/writeback.xml"))); //$NON-NLS-1$
+ return theRepository;
+ } finally {
+ if (bufferedInput != null)
+ bufferedInput.close();
+ }
+ } catch (IOException ioe) {
+ throw new RepositoryCreationException(ioe);
+ }
+ }
+
+ private interface XMLConstants extends org.eclipse.equinox.p2.core.helpers.XMLConstants {
+
+ // Constants defining the structure of the XML for a MetadataRepository
+
+ // A format version number for metadata repository XML.
+ public static final String XML_VERSION = "0.0.1"; //$NON-NLS-1$
+ public static final Version CURRENT_VERSION = new Version(XML_VERSION);
+ public static final VersionRange XML_TOLERANCE = new VersionRange(CURRENT_VERSION, true, CURRENT_VERSION, true);
+
+ // Constants for processing Instructions
+ public static final String PI_REPOSITORY_TARGET = "metadataRepository"; //$NON-NLS-1$
+ //public static XMLWriter.ProcessingInstruction[] PI_DEFAULTS = new XMLWriter.ProcessingInstruction[] {XMLWriter.ProcessingInstruction.makeClassVersionInstruction(PI_REPOSITORY_TARGET, IMetadataRepository.class, CURRENT_VERSION)};
+
+ // Constants for metadata repository elements
+ public static final String REPOSITORY_ELEMENT = "repository"; //$NON-NLS-1$
+ public static final String INSTALLABLE_UNITS_ELEMENT = "units"; //$NON-NLS-1$
+ public static final String INSTALLABLE_UNIT_ELEMENT = "unit"; //$NON-NLS-1$
+ public static final String PROCESSING_STEPS_ELEMENT = "processing"; //$NON-NLS-1$
+ public static final String PROCESSING_STEP_ELEMENT = "step"; //$NON-NLS-1$
+
+ // Constants for sub-elements of an installable unit element
+ public static final String ARTIFACT_KEYS_ELEMENT = "artifacts"; //$NON-NLS-1$
+ public static final String ARTIFACT_KEY_ELEMENT = "artifact"; //$NON-NLS-1$
+ public static final String REQUIRED_CAPABILITIES_ELEMENT = "requires"; //$NON-NLS-1$
+ public static final String REQUIRED_CAPABILITY_ELEMENT = "required"; //$NON-NLS-1$
+ public static final String PROVIDED_CAPABILITIES_ELEMENT = "provides"; //$NON-NLS-1$
+ public static final String PROVIDED_CAPABILITY_ELEMENT = "provided"; //$NON-NLS-1$
+ public static final String TOUCHPOINT_TYPE_ELEMENT = "touchpoint"; //$NON-NLS-1$
+ public static final String TOUCHPOINT_DATA_ELEMENT = "touchpointData"; //$NON-NLS-1$
+ public static final String IU_FILTER_ELEMENT = "filter"; //$NON-NLS-1$
+ public static final String APPLICABILITY_FILTER_ELEMENT = "applicability"; //$NON-NLS-1$
+
+ // Constants for attributes of an installable unit element
+ public static final String SINGLETON_ATTRIBUTE = "singleton"; //$NON-NLS-1$
+ public static final String FRAGMENT_ATTRIBUTE = "fragment"; //$NON-NLS-1$
+
+ // Constants for attributes of a fragment installable unit element
+ public static final String FRAGMENT_HOST_ID_ATTRIBUTE = "hostId"; //$NON-NLS-1$
+ public static final String FRAGMENT_HOST_RANGE_ATTRIBUTE = "hostRange"; //$NON-NLS-1$
+
+ // Constants for sub-elements of a required capability element
+ public static final String CAPABILITY_FILTER_ELEMENT = "filter"; //$NON-NLS-1$
+ public static final String CAPABILITY_SELECTORS_ELEMENT = "selectors"; //$NON-NLS-1$
+ public static final String CAPABILITY_SELECTOR_ELEMENT = "selector"; //$NON-NLS-1$
+
+ // Constants for attributes of a required capability element
+ public static final String CAPABILITY_OPTIONAL_ATTRIBUTE = "optional"; //$NON-NLS-1$
+ public static final String CAPABILITY_MULTIPLE_ATTRIBUTE = "multiple"; //$NON-NLS-1$
+
+ // Constants for attributes of an artifact key element
+ public static final String ARTIFACT_KEY_NAMESPACE_ATTRIBUTE = NAMESPACE_ATTRIBUTE;
+ public static final String ARTIFACT_KEY_CLASSIFIER_ATTRIBUTE = "classifier"; //$NON-NLS-1$
+
+ // Constants for sub-elements of a touchpoint data element
+ public static final String TOUCHPOINT_DATA_INSTRUCTIONS_ELEMENT = "instructions"; //$NON-NLS-1$
+ public static final String TOUCHPOINT_DATA_INSTRUCTION_ELEMENT = "instruction"; //$NON-NLS-1$
+
+ // Constants for attributes of an a touchpoint data instruction element
+ public static final String TOUCHPOINT_DATA_INSTRUCTION_KEY_ATTRIBUTE = "key"; //$NON-NLS-1$
+
+ }
+
+ protected XMLWriter.ProcessingInstruction[] createPI(Class repositoryClass) {
+ return new XMLWriter.ProcessingInstruction[] {XMLWriter.ProcessingInstruction.makeClassVersionInstruction(XMLConstants.PI_REPOSITORY_TARGET, repositoryClass, XMLConstants.CURRENT_VERSION)};
+ }
+
+ // XML writer for a IMetadataRepository
+ protected class Writer extends XMLWriter implements XMLConstants {
+
+ public Writer(OutputStream output, Class repositoryClass) throws IOException {
+ super(output, createPI(repositoryClass));
+ }
+
+ /**
+ * Write the given metadata repository to the output stream.
+ */
+ public void write(IMetadataRepository repository) {
+ start(REPOSITORY_ELEMENT);
+ attribute(NAME_ATTRIBUTE, repository.getName());
+ attribute(TYPE_ATTRIBUTE, repository.getType());
+ attribute(VERSION_ATTRIBUTE, repository.getVersion());
+ attributeOptional(PROVIDER_ATTRIBUTE, repository.getProvider());
+ attributeOptional(DESCRIPTION_ATTRIBUTE, repository.getDescription()); // TODO: could be cdata?
+
+ writeProperties(repository.getProperties());
+ writeInstallableUnits(getInstallableUnits(repository));
+
+ end(REPOSITORY_ELEMENT);
+ flush();
+ }
+
+ private IInstallableUnit[] getInstallableUnits(IMetadataRepository repository) {
+ // TODO: there is probably a better solution to the problem.
+ // TODO: Because the implementation of IMetadataRepository.getInstallableUnits
+ // in LocalMetadataRepository uses a query, the order of IUs is not preserved
+ // write after read. FIX THIS!
+ Set units = null;
+ if (repository instanceof LocalMetadataRepository) {
+ units = ((LocalMetadataRepository) repository).getInstallableUnits();
+ } else if (repository instanceof URLMetadataRepository) {
+ units = ((URLMetadataRepository) repository).getInstallableUnits();
+ } else {
+ return repository.getInstallableUnits(new NullProgressMonitor());
+ }
+ return (units == null ? new IInstallableUnit[0] //
+ : (IInstallableUnit[]) units.toArray(new IInstallableUnit[units.size()]));
+ }
+
+ private void writeInstallableUnits(IInstallableUnit[] installableUnits) {
+ if (installableUnits.length > 0) {
+ start(INSTALLABLE_UNITS_ELEMENT);
+ attribute(COLLECTION_SIZE_ATTRIBUTE, installableUnits.length);
+ for (int i = 0; i < installableUnits.length; i++) {
+ writeInstallableUnit(installableUnits[i]);
+ }
+ end(INSTALLABLE_UNITS_ELEMENT);
+ }
+ }
+
+ private void writeInstallableUnit(IInstallableUnit resolvedIU) {
+ IInstallableUnit iu = (!(resolvedIU instanceof IResolvedInstallableUnit) ? resolvedIU//
+ : ((IResolvedInstallableUnit) resolvedIU).getOriginal());
+ start(INSTALLABLE_UNIT_ELEMENT);
+ attribute(ID_ATTRIBUTE, iu.getId());
+ attribute(VERSION_ATTRIBUTE, iu.getVersion());
+ attribute(SINGLETON_ATTRIBUTE, iu.isSingleton(), true);
+ attribute(FRAGMENT_ATTRIBUTE, iu.isFragment(), false);
+
+ if (iu.isFragment() && iu instanceof IInstallableUnitFragment) {
+ IInstallableUnitFragment fragment = (IInstallableUnitFragment) iu;
+ attribute(FRAGMENT_HOST_ID_ATTRIBUTE, fragment.getHostId());
+ attribute(FRAGMENT_HOST_RANGE_ATTRIBUTE, fragment.getHostVersionRange());
+ }
+
+ writeProperties(iu.getProperties());
+ writeProvidedCapabilities(iu.getProvidedCapabilities());
+ writeRequiredCapabilities(iu.getRequiredCapabilities());
+ writeTrimmedCdata(IU_FILTER_ELEMENT, iu.getFilter());
+ writeTrimmedCdata(APPLICABILITY_FILTER_ELEMENT, iu.getApplicabilityFilter());
+
+ writeArtifactKeys(iu.getArtifacts());
+ writeTouchpointType(iu.getTouchpointType());
+ writeTouchpointData(iu.getTouchpointData());
+
+ end(INSTALLABLE_UNIT_ELEMENT);
+ }
+
+ private void writeProvidedCapabilities(ProvidedCapability[] capabilities) {
+ if (capabilities != null && capabilities.length > 0) {
+ start(PROVIDED_CAPABILITIES_ELEMENT);
+ attribute(COLLECTION_SIZE_ATTRIBUTE, capabilities.length);
+ for (int i = 0; i < capabilities.length; i++) {
+ start(PROVIDED_CAPABILITY_ELEMENT);
+ attribute(NAMESPACE_ATTRIBUTE, capabilities[i].getNamespace());
+ attribute(NAME_ATTRIBUTE, capabilities[i].getName());
+ attribute(VERSION_ATTRIBUTE, capabilities[i].getVersion());
+ end(PROVIDED_CAPABILITY_ELEMENT);
+ }
+ end(PROVIDED_CAPABILITIES_ELEMENT);
+ }
+ }
+
+ private void writeRequiredCapabilities(RequiredCapability[] capabilities) {
+ if (capabilities != null && capabilities.length > 0) {
+ start(REQUIRED_CAPABILITIES_ELEMENT);
+ attribute(COLLECTION_SIZE_ATTRIBUTE, capabilities.length);
+ for (int i = 0; i < capabilities.length; i++) {
+ writeRequiredCapability(capabilities[i]);
+ }
+ end(REQUIRED_CAPABILITIES_ELEMENT);
+ }
+ }
+
+ private void writeRequiredCapability(RequiredCapability capability) {
+ start(REQUIRED_CAPABILITY_ELEMENT);
+ attribute(NAMESPACE_ATTRIBUTE, capability.getNamespace());
+ attribute(NAME_ATTRIBUTE, capability.getName());
+ attribute(VERSION_RANGE_ATTRIBUTE, capability.getRange());
+ attribute(CAPABILITY_OPTIONAL_ATTRIBUTE, capability.isOptional(), false);
+ attribute(CAPABILITY_MULTIPLE_ATTRIBUTE, capability.isMultiple(), false);
+
+ writeTrimmedCdata(CAPABILITY_FILTER_ELEMENT, capability.getFilter());
+
+ String[] selectors = capability.getSelectors();
+ if (selectors.length > 0) {
+ start(CAPABILITY_SELECTORS_ELEMENT);
+ attribute(COLLECTION_SIZE_ATTRIBUTE, selectors.length);
+ for (int j = 0; j < selectors.length; j++) {
+ writeTrimmedCdata(CAPABILITY_SELECTOR_ELEMENT, selectors[j]);
+ }
+ end(CAPABILITY_SELECTORS_ELEMENT);
+ }
+
+ end(REQUIRED_CAPABILITY_ELEMENT);
+ }
+
+ private void writeArtifactKeys(IArtifactKey[] artifactKeys) {
+ if (artifactKeys != null && artifactKeys.length > 0) {
+ start(ARTIFACT_KEYS_ELEMENT);
+ attribute(COLLECTION_SIZE_ATTRIBUTE, artifactKeys.length);
+ for (int i = 0; i < artifactKeys.length; i++) {
+ start(ARTIFACT_KEY_ELEMENT);
+ attribute(ARTIFACT_KEY_NAMESPACE_ATTRIBUTE, artifactKeys[i].getNamespace());
+ attribute(ARTIFACT_KEY_CLASSIFIER_ATTRIBUTE, artifactKeys[i].getClassifier());
+ attribute(ID_ATTRIBUTE, artifactKeys[i].getId());
+ attribute(VERSION_ATTRIBUTE, artifactKeys[i].getVersion());
+ end(ARTIFACT_KEY_ELEMENT);
+ }
+ end(ARTIFACT_KEYS_ELEMENT);
+ }
+ }
+
+ private void writeTouchpointType(TouchpointType touchpointType) {
+ start(TOUCHPOINT_TYPE_ELEMENT);
+ attribute(ID_ATTRIBUTE, touchpointType.getId());
+ attribute(VERSION_ATTRIBUTE, touchpointType.getVersion());
+ end(TOUCHPOINT_TYPE_ELEMENT);
+ }
+
+ private void writeTouchpointData(TouchpointData[] touchpointData) {
+ if (touchpointData != null && touchpointData.length > 0) {
+ start(TOUCHPOINT_DATA_ELEMENT);
+ attribute(COLLECTION_SIZE_ATTRIBUTE, touchpointData.length);
+ for (int i = 0; i < touchpointData.length; i++) {
+ TouchpointData nextData = touchpointData[i];
+ Map instructions = nextData.getInstructions();
+ if (instructions.size() > 0) {
+ start(TOUCHPOINT_DATA_INSTRUCTIONS_ELEMENT);
+ attribute(COLLECTION_SIZE_ATTRIBUTE, instructions.size());
+ for (Iterator iter = instructions.entrySet().iterator(); iter.hasNext();) {
+ Map.Entry entry = (Map.Entry) iter.next();
+ start(TOUCHPOINT_DATA_INSTRUCTION_ELEMENT);
+ attribute(TOUCHPOINT_DATA_INSTRUCTION_KEY_ATTRIBUTE, entry.getKey());
+ cdataLines((String) entry.getValue(), true);
+ end(TOUCHPOINT_DATA_INSTRUCTION_ELEMENT);
+ }
+ }
+ }
+ end(TOUCHPOINT_DATA_ELEMENT);
+ }
+ }
+
+ private void writeTrimmedCdata(String element, String filter) {
+ String trimmed;
+ if (filter != null && (trimmed = filter.trim()).length() > 0) {
+ start(element);
+ cdata(trimmed);
+ end(element);
+ }
+ }
+ }
+
+ /*
+ * Parser for the contents of a LocalMetadata,
+ * as written by the Writer class.
+ */
+ private class Parser extends XMLParser implements XMLConstants {
+
+ private IMetadataRepository theRepository = null;
+ protected Class theRepositoryClass = LocalMetadataRepository.class;
+
+ public Parser(BundleContext context, String bundleId) {
+ super(context, bundleId);
+ }
+
+ public void parse(File file) throws IOException {
+ parse(new FileInputStream(file));
+ }
+
+ public synchronized void parse(InputStream stream) throws IOException {
+ this.status = null;
+ try {
+ // TODO: currently not caching the parser since we make no assumptions
+ // or restrictions on concurrent parsing
+ getParser();
+ RepositoryHandler repositoryHandler = new RepositoryHandler();
+ xmlReader.setContentHandler(new RepositoryDocHandler(REPOSITORY_ELEMENT, repositoryHandler));
+ xmlReader.parse(new InputSource(stream));
+ if (isValidXML()) {
+ theRepository = repositoryHandler.getRepository();
+ }
+ } catch (SAXException e) {
+ throw new IOException(e.getMessage());
+ } catch (ParserConfigurationException e) {
+ throw new IOException(e.getMessage());
+ } finally {
+ stream.close();
+ }
+ }
+
+ public IMetadataRepository getRepository() {
+ return theRepository;
+ }
+
+ public Class getRepositoryClass() {
+ return theRepositoryClass;
+ }
+
+ protected Object getRootObject() {
+ return theRepository;
+ }
+
+ public void ProcessingInstruction(String target, String data) throws SAXException {
+ if (PI_REPOSITORY_TARGET.equalsIgnoreCase(target)) {
+ // TODO: should the root handler be constructed based on class
+ // via an extension registry mechanism?
+ String clazz = extractPIClass(data);
+ try {
+ theRepositoryClass = Class.forName(clazz);
+ } catch (ClassNotFoundException e) {
+ // throw new SAXException(NLS.bind(Messages.MetadataRepositoryIO_Repository_Class_Not_Found, clazz));
+ throw new SAXException("Metadata repository class " + clazz + "not found"); //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ // TODO: version tolerance by extension
+ Version repositoryVersion = extractPIVersion(target, data);
+ if (!XML_TOLERANCE.isIncluded(repositoryVersion)) {
+ throw new SAXException(NLS.bind(Messages.MetadataRepositoryIO_Parser_Has_Incompatible_Version, repositoryVersion, XML_TOLERANCE));
+ }
+ }
+ }
+
+ private final class RepositoryDocHandler extends DocHandler {
+
+ public RepositoryDocHandler(String rootName, RootHandler rootHandler) {
+ super(rootName, rootHandler);
+ }
+ }
+
+ private final class RepositoryHandler extends RootHandler {
+
+ private final String[] required = new String[] {NAME_ATTRIBUTE, TYPE_ATTRIBUTE, VERSION_ATTRIBUTE};
+ private final String[] optional = new String[] {DESCRIPTION_ATTRIBUTE, PROVIDER_ATTRIBUTE};
+
+ private InstallableUnitsHandler unitsHandler = null;
+ private PropertiesHandler propertiesHandler = null;
+
+ private AbstractMetadataRepository repository = null;
+
+ private RepositoryState state = new RepositoryState();
+
+ public RepositoryHandler() {
+ super();
+ }
+
+ public IMetadataRepository getRepository() {
+ return repository;
+ }
+
+ protected void handleRootAttributes(Attributes attributes) {
+ String[] values = parseAttributes(attributes, required, optional);
+ Version version = checkVersion(this.elementHandled, VERSION_ATTRIBUTE, values[2]);
+ state.Name = values[0];
+ state.Type = values[1];
+ state.Version = version;
+ state.Description = values[3];
+ state.Provider = values[4];
+ state.Location = null; // new URL("file://C:/bogus");
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (PROPERTIES_ELEMENT.equalsIgnoreCase(name)) {
+ if (propertiesHandler == null) {
+ propertiesHandler = new PropertiesHandler(this, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else if (INSTALLABLE_UNITS_ELEMENT.equalsIgnoreCase(name)) {
+ if (unitsHandler == null) {
+ unitsHandler = new InstallableUnitsHandler(this, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+
+ protected void finished() {
+ if (isValidXML()) {
+ // // TODO: need to support URLMetadataRepository as well.
+ // try {
+ // repository = new LocalMetadataRepository(attrValues[0], attrValues[1], attrValues[2], new URL("file://C:/bogus"), attrValues[3], attrValues[4]);
+ // } catch (MalformedURLException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ // }
+ state.Properties = (propertiesHandler == null ? new OrderedProperties(0) //
+ : propertiesHandler.getProperties());
+ state.Units = (unitsHandler == null ? new IInstallableUnit[0] //
+ : unitsHandler.getUnits());
+ try {
+ Object repositoryObject = theRepositoryClass.newInstance();
+ if (repositoryObject instanceof AbstractMetadataRepository) {
+ repository = (AbstractMetadataRepository) repositoryObject;
+ repository.initialize(state);
+ }
+ } catch (InstantiationException e) {
+ // TODO: Throw a SAXException
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ // TODO: Throw a SAXException
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ protected class InstallableUnitsHandler extends AbstractHandler {
+
+ private ArrayList units;
+
+ public InstallableUnitsHandler(AbstractHandler parentHandler, Attributes attributes) {
+ super(parentHandler, INSTALLABLE_UNITS_ELEMENT);
+ String size = parseOptionalAttribute(attributes, COLLECTION_SIZE_ATTRIBUTE);
+ units = (size != null ? new ArrayList(new Integer(size).intValue()) : new ArrayList(4));
+ }
+
+ public IInstallableUnit[] getUnits() {
+ return (IInstallableUnit[]) units.toArray(new IInstallableUnit[units.size()]);
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equalsIgnoreCase(INSTALLABLE_UNIT_ELEMENT)) {
+ new InstallableUnitHandler(this, attributes, units);
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+ }
+
+ protected class InstallableUnitHandler extends AbstractHandler {
+
+ private final String[] required = new String[] {ID_ATTRIBUTE, VERSION_ATTRIBUTE};
+ private final String[] optional = new String[] {SINGLETON_ATTRIBUTE, FRAGMENT_ATTRIBUTE, FRAGMENT_HOST_ID_ATTRIBUTE, FRAGMENT_HOST_RANGE_ATTRIBUTE};
+
+ InstallableUnit currentUnit = null;
+
+ private PropertiesHandler propertiesHandler = null;
+ private ProvidedCapabilitiesHandler providedCapabilitiesHandler = null;
+ private RequiredCapabilitiesHandler requiredCapabilitiesHandler = null;
+ private TextHandler filterHandler = null;
+ private TextHandler applicabilityHandler = null;
+ private ArtifactsHandler artifactsHandler = null;
+ private TouchpointTypeHandler touchpointTypeHandler = null;
+ private TouchpointDataHandler touchpointDataHandler = null;
+
+ public InstallableUnitHandler(AbstractHandler parentHandler, Attributes attributes, List units) {
+ super(parentHandler, INSTALLABLE_UNIT_ELEMENT);
+ String[] values = parseAttributes(attributes, required, optional);
+
+ Version version = checkVersion(INSTALLABLE_UNIT_ELEMENT, VERSION_ATTRIBUTE, values[1]);
+ boolean singleton = checkBoolean(INSTALLABLE_UNIT_ELEMENT, SINGLETON_ATTRIBUTE, values[2], true).booleanValue();
+ boolean isFragment = checkBoolean(INSTALLABLE_UNIT_ELEMENT, FRAGMENT_ATTRIBUTE, values[3], false).booleanValue();
+ if (isFragment) {
+ // TODO: tooling default fragment does not have a host id
+ // checkRequiredAttribute(INSTALLABLE_UNIT_ELEMENT, FRAGMENT_HOST_ID_ATTRIBUTE, values[4]);
+ checkRequiredAttribute(INSTALLABLE_UNIT_ELEMENT, FRAGMENT_HOST_RANGE_ATTRIBUTE, values[5]);
+ VersionRange hostRange = checkVersionRange(INSTALLABLE_UNIT_ELEMENT, FRAGMENT_HOST_RANGE_ATTRIBUTE, values[5]);
+ currentUnit = new InstallableUnitFragment(values[0], version, singleton, values[4], hostRange);
+ } else {
+ if (values[4] != null) {
+ unexpectedAttribute(INSTALLABLE_UNIT_ELEMENT, FRAGMENT_HOST_ID_ATTRIBUTE, values[4]);
+ } else if (values[5] != null) {
+ unexpectedAttribute(INSTALLABLE_UNIT_ELEMENT, FRAGMENT_HOST_RANGE_ATTRIBUTE, values[4]);
+ }
+ currentUnit = new InstallableUnit(values[0], version, singleton);
+ }
+ units.add(currentUnit);
+ }
+
+ public IInstallableUnit getInstallableUnit() {
+ return currentUnit;
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (PROPERTIES_ELEMENT.equalsIgnoreCase(name)) {
+ if (propertiesHandler == null) {
+ propertiesHandler = new PropertiesHandler(this, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else if (PROVIDED_CAPABILITIES_ELEMENT.equalsIgnoreCase(name)) {
+ if (providedCapabilitiesHandler == null) {
+ providedCapabilitiesHandler = new ProvidedCapabilitiesHandler(this, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else if (REQUIRED_CAPABILITIES_ELEMENT.equalsIgnoreCase(name)) {
+ if (requiredCapabilitiesHandler == null) {
+ requiredCapabilitiesHandler = new RequiredCapabilitiesHandler(this, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else if (IU_FILTER_ELEMENT.equalsIgnoreCase(name)) {
+ if (filterHandler == null) {
+ filterHandler = new TextHandler(this, IU_FILTER_ELEMENT, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else if (APPLICABILITY_FILTER_ELEMENT.equalsIgnoreCase(name)) {
+ if (applicabilityHandler == null) {
+ applicabilityHandler = new TextHandler(this, APPLICABILITY_FILTER_ELEMENT, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else if (ARTIFACT_KEYS_ELEMENT.equalsIgnoreCase(name)) {
+ if (artifactsHandler == null) {
+ artifactsHandler = new ArtifactsHandler(this, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else if (TOUCHPOINT_TYPE_ELEMENT.equalsIgnoreCase(name)) {
+ if (touchpointTypeHandler == null) {
+ touchpointTypeHandler = new TouchpointTypeHandler(this, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else if (TOUCHPOINT_DATA_ELEMENT.equalsIgnoreCase(name)) {
+ if (touchpointDataHandler == null) {
+ touchpointDataHandler = new TouchpointDataHandler(this, attributes);
+ } else {
+ duplicateElement(this, name, attributes);
+ }
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+
+ protected void finished() {
+ if (isValidXML() && currentUnit != null) {
+ OrderedProperties properties = (propertiesHandler == null ? new OrderedProperties(0) //
+ : propertiesHandler.getProperties());
+ currentUnit.addProperties(properties);
+ ProvidedCapability[] providedCapabilities = (providedCapabilitiesHandler == null ? new ProvidedCapability[0] //
+ : providedCapabilitiesHandler.getProvidedCapabilities());
+ currentUnit.setCapabilities(providedCapabilities);
+ RequiredCapability[] requiredCapabilities = (requiredCapabilitiesHandler == null ? new RequiredCapability[0] //
+ : requiredCapabilitiesHandler.getRequiredCapabilities());
+ currentUnit.setRequiredCapabilities(requiredCapabilities);
+ if (filterHandler != null) {
+ currentUnit.setFilter(filterHandler.getText());
+ }
+ if (applicabilityHandler != null) {
+ currentUnit.setApplicabilityFilter(applicabilityHandler.getText());
+ }
+ IArtifactKey[] artifacts = (artifactsHandler == null ? new IArtifactKey[0] //
+ : artifactsHandler.getArtifactKeys());
+ currentUnit.setArtifacts(artifacts);
+ if (touchpointTypeHandler != null) {
+ currentUnit.setTouchpointType(touchpointTypeHandler.getTouchpointType());
+ } else {
+ // TODO: create an error
+ }
+ TouchpointData[] touchpointData = (touchpointDataHandler == null ? new TouchpointData[0] //
+ : touchpointDataHandler.getTouchpointData());
+ currentUnit.addTouchpointData(touchpointData);
+ }
+ }
+ }
+
+ protected class ProvidedCapabilitiesHandler extends AbstractHandler {
+
+ private List providedCapabilities;
+
+ public ProvidedCapabilitiesHandler(AbstractHandler parentHandler, Attributes attributes) {
+ super(parentHandler, PROVIDED_CAPABILITIES_ELEMENT);
+ String size = parseOptionalAttribute(attributes, COLLECTION_SIZE_ATTRIBUTE);
+ providedCapabilities = (size != null ? new ArrayList(new Integer(size).intValue()) : new ArrayList(4));
+ }
+
+ public ProvidedCapability[] getProvidedCapabilities() {
+ return (ProvidedCapability[]) providedCapabilities.toArray(new ProvidedCapability[providedCapabilities.size()]);
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equalsIgnoreCase(PROVIDED_CAPABILITY_ELEMENT)) {
+ new ProvidedCapabilityHandler(this, attributes, providedCapabilities);
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+ }
+
+ protected class ProvidedCapabilityHandler extends AbstractHandler {
+
+ private final String[] required = new String[] {NAMESPACE_ATTRIBUTE, NAME_ATTRIBUTE, VERSION_ATTRIBUTE};
+
+ public ProvidedCapabilityHandler(AbstractHandler parentHandler, Attributes attributes, List capabilities) {
+ super(parentHandler, PROVIDED_CAPABILITY_ELEMENT);
+ String[] values = parseRequiredAttributes(attributes, required);
+ Version version = checkVersion(PROVIDED_CAPABILITY_ELEMENT, VERSION_ATTRIBUTE, values[2]);
+ capabilities.add(new ProvidedCapability(values[0], values[1], version));
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ invalidElement(name, attributes);
+ }
+ }
+
+ protected class RequiredCapabilitiesHandler extends AbstractHandler {
+
+ private List requiredCapabilities;
+
+ public RequiredCapabilitiesHandler(AbstractHandler parentHandler, Attributes attributes) {
+ super(parentHandler, REQUIRED_CAPABILITIES_ELEMENT);
+ String size = parseOptionalAttribute(attributes, COLLECTION_SIZE_ATTRIBUTE);
+ requiredCapabilities = (size != null ? new ArrayList(new Integer(size).intValue()) : new ArrayList(4));
+ }
+
+ public RequiredCapability[] getRequiredCapabilities() {
+ return (RequiredCapability[]) requiredCapabilities.toArray(new RequiredCapability[requiredCapabilities.size()]);
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equalsIgnoreCase(REQUIRED_CAPABILITY_ELEMENT)) {
+ new RequiredCapabilityHandler(this, attributes, requiredCapabilities);
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+ }
+
+ protected class RequiredCapabilityHandler extends AbstractHandler {
+
+ private final String[] required = new String[] {NAMESPACE_ATTRIBUTE, NAME_ATTRIBUTE, VERSION_RANGE_ATTRIBUTE};
+ private final String[] optional = new String[] {CAPABILITY_OPTIONAL_ATTRIBUTE, CAPABILITY_MULTIPLE_ATTRIBUTE};
+
+ private RequiredCapability currentCapability = null;
+
+ private TextHandler filterHandler = null;
+ private CapabilitySelectorsHandler selectorsHandler = null;
+
+ public RequiredCapabilityHandler(AbstractHandler parentHandler, Attributes attributes, List capabilities) {
+ super(parentHandler, REQUIRED_CAPABILITY_ELEMENT);
+ String[] values = parseAttributes(attributes, required, optional);
+ VersionRange range = checkVersionRange(REQUIRED_CAPABILITY_ELEMENT, VERSION_RANGE_ATTRIBUTE, values[2]);
+ boolean isOptional = checkBoolean(REQUIRED_CAPABILITY_ELEMENT, CAPABILITY_OPTIONAL_ATTRIBUTE, values[3], false).booleanValue();
+ boolean isMultiple = checkBoolean(REQUIRED_CAPABILITY_ELEMENT, CAPABILITY_MULTIPLE_ATTRIBUTE, values[4], false).booleanValue();
+ currentCapability = new RequiredCapability(values[0], values[1], range, null, isOptional, isMultiple);
+ capabilities.add(currentCapability);
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equalsIgnoreCase(CAPABILITY_FILTER_ELEMENT)) {
+ filterHandler = new TextHandler(this, CAPABILITY_FILTER_ELEMENT, attributes);
+ } else if (name.equalsIgnoreCase(CAPABILITY_SELECTORS_ELEMENT)) {
+ selectorsHandler = new CapabilitySelectorsHandler(this, attributes);
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+
+ protected void finished() {
+ if (isValidXML()) {
+ if (currentCapability != null) {
+ if (filterHandler != null) {
+ currentCapability.setFilter(filterHandler.getText());
+ }
+ if (selectorsHandler != null) {
+ currentCapability.setSelectors(selectorsHandler.getSelectors());
+ }
+ }
+ }
+ }
+ }
+
+ protected class ArtifactsHandler extends AbstractHandler {
+
+ private List artifacts;
+
+ public ArtifactsHandler(AbstractHandler parentHandler, Attributes attributes) {
+ super(parentHandler, ARTIFACT_KEYS_ELEMENT);
+ String size = parseOptionalAttribute(attributes, COLLECTION_SIZE_ATTRIBUTE);
+ artifacts = (size != null ? new ArrayList(new Integer(size).intValue()) : new ArrayList(4));
+ }
+
+ public IArtifactKey[] getArtifactKeys() {
+ return (IArtifactKey[]) artifacts.toArray(new IArtifactKey[artifacts.size()]);
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equalsIgnoreCase(ARTIFACT_KEY_ELEMENT)) {
+ new ArtifactHandler(this, attributes, artifacts);
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+ }
+
+ protected class ArtifactHandler extends AbstractHandler {
+
+ private final String[] required = new String[] {NAMESPACE_ATTRIBUTE, CLASSIFIER_ATTRIBUTE, ID_ATTRIBUTE, VERSION_ATTRIBUTE};
+
+ public ArtifactHandler(AbstractHandler parentHandler, Attributes attributes, List artifacts) {
+ super(parentHandler, ARTIFACT_KEY_ELEMENT);
+ String[] values = parseRequiredAttributes(attributes, required);
+ Version version = checkVersion(ARTIFACT_KEY_ELEMENT, VERSION_ATTRIBUTE, values[3]);
+ artifacts.add(new ArtifactKey(values[0], values[1], values[2], version));
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ invalidElement(name, attributes);
+ }
+ }
+
+ protected class CapabilitySelectorsHandler extends AbstractHandler {
+
+ private List selectors;
+
+ public CapabilitySelectorsHandler(AbstractHandler parentHandler, Attributes attributes) {
+ super(parentHandler, CAPABILITY_SELECTORS_ELEMENT);
+ String size = parseOptionalAttribute(attributes, COLLECTION_SIZE_ATTRIBUTE);
+ selectors = (size != null ? new ArrayList(new Integer(size).intValue()) : new ArrayList(4));
+ }
+
+ public String[] getSelectors() {
+ return (String[]) selectors.toArray(new String[selectors.size()]);
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equalsIgnoreCase(CAPABILITY_SELECTOR_ELEMENT)) {
+ new TextHandler(this, CAPABILITY_SELECTOR_ELEMENT, attributes, selectors);
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+ }
+
+ protected class TouchpointTypeHandler extends AbstractHandler {
+
+ private final String[] required = new String[] {ID_ATTRIBUTE, VERSION_ATTRIBUTE};
+
+ TouchpointType touchpointType = null;
+
+ public TouchpointTypeHandler(AbstractHandler parentHandler, Attributes attributes) {
+ super(parentHandler, TOUCHPOINT_TYPE_ELEMENT);
+ String[] values = parseRequiredAttributes(attributes, required);
+ Version version = checkVersion(TOUCHPOINT_TYPE_ELEMENT, VERSION_ATTRIBUTE, values[1]);
+ touchpointType = new TouchpointType(values[0], version);
+ }
+
+ public TouchpointType getTouchpointType() {
+ return touchpointType;
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ invalidElement(name, attributes);
+ }
+ }
+
+ protected class TouchpointDataHandler extends AbstractHandler {
+
+ TouchpointData touchpointData = null;
+
+ List data = null;
+
+ public TouchpointDataHandler(AbstractHandler parentHandler, Attributes attributes) {
+ super(parentHandler, TOUCHPOINT_DATA_ELEMENT);
+ String size = parseOptionalAttribute(attributes, COLLECTION_SIZE_ATTRIBUTE);
+ data = (size != null ? new ArrayList(new Integer(size).intValue()) : new ArrayList(4));
+ }
+
+ public TouchpointData[] getTouchpointData() {
+ return (TouchpointData[]) data.toArray(new TouchpointData[data.size()]);
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equalsIgnoreCase(TOUCHPOINT_DATA_INSTRUCTIONS_ELEMENT)) {
+ new TouchpointInstructionsHandler(this, attributes, data);
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+ }
+
+ protected class TouchpointInstructionsHandler extends AbstractHandler {
+
+ Map instructions = null;
+
+ public TouchpointInstructionsHandler(AbstractHandler parentHandler, Attributes attributes, List data) {
+ super(parentHandler, TOUCHPOINT_DATA_INSTRUCTIONS_ELEMENT);
+ String size = parseOptionalAttribute(attributes, COLLECTION_SIZE_ATTRIBUTE);
+ instructions = (size != null ? new LinkedHashMap(new Integer(size).intValue()) : new LinkedHashMap(4));
+ data.add(new TouchpointData(instructions));
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equalsIgnoreCase(TOUCHPOINT_DATA_INSTRUCTION_ELEMENT)) {
+ new TouchpointInstructionHandler(this, attributes, instructions);
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+ }
+
+ protected class TouchpointInstructionHandler extends TextHandler {
+
+ private final String[] required = new String[] {TOUCHPOINT_DATA_INSTRUCTION_KEY_ATTRIBUTE};
+
+ Map instructions = null;
+ String key = null;
+
+ public TouchpointInstructionHandler(AbstractHandler parentHandler, Attributes attributes, Map instructions) {
+ super(parentHandler, TOUCHPOINT_DATA_INSTRUCTION_ELEMENT);
+ key = parseRequiredAttributes(attributes, required)[0];
+ this.instructions = instructions;
+ }
+
+ protected void finished() {
+ if (isValidXML()) {
+ if (key != null) {
+ instructions.put(key, getText());
+ }
+ }
+ }
+ }
+
+ protected String getErrorMessage() {
+ return Messages.MetadataRepositoryIO_Parser_Error_Parsing_Repository;
+ }
+
+ public String toString() {
+ // TODO:
+ return null;
+ }
+ }
}
diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/URLMetadataRepository.java b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/URLMetadataRepository.java
index 9fee1d394..06129b76a 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/URLMetadataRepository.java
+++ b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/URLMetadataRepository.java
@@ -13,14 +13,12 @@ package org.eclipse.equinox.internal.p2.metadata.repository;
import java.net.MalformedURLException;
import java.net.URL;
-import java.util.HashSet;
-import java.util.Iterator;
+import java.util.*;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.equinox.p2.core.repository.RepositoryCreationException;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.RequiredCapability;
-import org.eclipse.equinox.p2.metadata.repository.IMetadataRepository;
import org.eclipse.equinox.p2.query.CompoundIterator;
import org.eclipse.equinox.spi.p2.metadata.repository.AbstractMetadataRepository;
import org.eclipse.osgi.service.resolver.VersionRange;
@@ -29,14 +27,14 @@ import org.eclipse.osgi.util.NLS;
/**
* A metadata repository backed by an arbitrary URL.
*/
-public class URLMetadataRepository extends AbstractMetadataRepository implements IMetadataRepository {
+public class URLMetadataRepository extends AbstractMetadataRepository {
static final private String REPOSITORY_TYPE = URLMetadataRepository.class.getName();
static final private Integer REPOSITORY_VERSION = new Integer(1);
static final protected String CONTENT_FILENAME = "content.xml"; //$NON-NLS-1$
transient protected URL content;
- protected HashSet units = new HashSet();
+ protected HashSet units = new LinkedHashSet();
public static URL getActualLocation(URL base) {
String spec = base.toExternalForm();
@@ -58,10 +56,14 @@ public class URLMetadataRepository extends AbstractMetadataRepository implements
}
public URLMetadataRepository(URL location, String name) {
- super(name == null ? (location != null ? location.toExternalForm() : "") : name, REPOSITORY_TYPE, REPOSITORY_VERSION.toString(), location, null, null);
+ super(name == null ? (location != null ? location.toExternalForm() : "") : name, REPOSITORY_TYPE, REPOSITORY_VERSION.toString(), location, null, null); //$NON-NLS-1$
content = getActualLocation(location);
}
+ public URLMetadataRepository() {
+ super();
+ }
+
protected boolean load() throws RepositoryCreationException {
return new SimpleMetadataRepositoryFactory().load(location) != null;
}
@@ -106,4 +108,21 @@ public class URLMetadataRepository extends AbstractMetadataRepository implements
public boolean isModifiable() {
return false;
}
+
+ // Get a non-modifiable collection of the installable units
+ // from the repository.
+ public Set getInstallableUnits() {
+ return Collections.unmodifiableSet(units);
+ }
+
+ public void initialize(RepositoryState state) {
+ this.name = state.Name;
+ this.type = state.Type;
+ this.version = state.Version.toString();
+ this.provider = state.Provider;
+ this.description = state.Description;
+ this.location = state.Location;
+ this.properties = state.Properties;
+ this.units.addAll(Arrays.asList(state.Units));
+ }
}
diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/messages.properties b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/messages.properties
index fc369d7ab..cf9c00596 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/messages.properties
+++ b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/messages.properties
@@ -10,4 +10,9 @@
###############################################################################
REPO_LOADING = Loading the repository {0}
-REPOMGR_ADDING_REPO = Adding repository {0} \ No newline at end of file
+REPOMGR_ADDING_REPO = Adding repository {0}
+
+MetadataRepositoryIO_Parser_Has_Incompatible_Version=\
+ Metadata repository has incompatible version {0}; expected {1}
+MetadataRepositoryIO_Parser_Error_Parsing_Repository=\
+ Error parsing metadata repository
diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/spi/p2/metadata/repository/AbstractMetadataRepository.java b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/spi/p2/metadata/repository/AbstractMetadataRepository.java
index 99fc32ea5..046dedb2d 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/spi/p2/metadata/repository/AbstractMetadataRepository.java
+++ b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/spi/p2/metadata/repository/AbstractMetadataRepository.java
@@ -11,12 +11,31 @@
package org.eclipse.equinox.spi.p2.metadata.repository;
import java.net.URL;
+import org.eclipse.equinox.p2.core.helpers.OrderedProperties;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.repository.IMetadataRepository;
import org.eclipse.equinox.spi.p2.core.repository.AbstractRepository;
+import org.osgi.framework.Version;
public abstract class AbstractMetadataRepository extends AbstractRepository implements IMetadataRepository {
+ public static class RepositoryState {
+ public String Name;
+ public String Type;
+ public Version Version;
+ public String Provider;
+ public String Description;
+ public URL Location;
+ public OrderedProperties Properties;
+ public IInstallableUnit[] Units;
+ }
+
+ public AbstractMetadataRepository() {
+ super("noName", "noType", "noVersion", null, null, null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ public abstract void initialize(RepositoryState state);
+
protected AbstractMetadataRepository(String name, String type, String version, URL location, String description, String provider) {
super(name, type, version, location, description, provider);
}
diff --git a/bundles/org.eclipse.equinox.p2.metadata/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.metadata/META-INF/MANIFEST.MF
index 1eb5ca45b..128f69c30 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.p2.metadata/META-INF/MANIFEST.MF
@@ -5,7 +5,7 @@ Bundle-Name: %pluginName
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Bundle-Version: 0.1.0.qualifier
-Export-Package: org.eclipse.equinox.internal.p2.metadata;x-friends:="org.eclipse.equinox.p2.metadata.generator",
+Export-Package: org.eclipse.equinox.internal.p2.metadata;x-friends:="org.eclipse.equinox.p2.metadata.generator, org.eclipse.equinox.p2.metadata.repository",
org.eclipse.equinox.p2.metadata,
org.eclipse.equinox.p2.query,
org.eclipse.equinox.p2.resolution
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/IInstallableUnit.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/IInstallableUnit.java
index eeb5e5f2f..0849155a3 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/IInstallableUnit.java
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/IInstallableUnit.java
@@ -8,6 +8,7 @@
******************************************************************************/
package org.eclipse.equinox.p2.metadata;
+import org.eclipse.equinox.p2.core.helpers.OrderedProperties;
import org.osgi.framework.Version;
public interface IInstallableUnit extends Comparable {
@@ -62,6 +63,8 @@ public interface IInstallableUnit extends Comparable {
public abstract String getProperty(String key);
+ public abstract OrderedProperties getProperties();
+
public abstract TouchpointData[] getTouchpointData();
public abstract boolean isFragment();
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/InstallableUnit.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/InstallableUnit.java
index f0873c0c0..c2b49c6fe 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/InstallableUnit.java
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/InstallableUnit.java
@@ -8,6 +8,7 @@
******************************************************************************/
package org.eclipse.equinox.p2.metadata;
+import java.util.ArrayList;
import org.eclipse.equinox.internal.p2.metadata.InternalInstallableUnit;
import org.eclipse.equinox.p2.core.helpers.OrderedProperties;
import org.eclipse.equinox.p2.core.helpers.UnmodifiableProperties;
@@ -26,7 +27,7 @@ public class InstallableUnit implements IInstallableUnitConstants, IInstallableU
private IArtifactKey[] artifacts;
private TouchpointType touchpointType;
- private TouchpointData immutableTouchpointData;
+ private ArrayList touchpointData = null;
private RequiredCapability[] requires;
@@ -40,6 +41,14 @@ public class InstallableUnit implements IInstallableUnitConstants, IInstallableU
super();
}
+ public InstallableUnit(String id, Version version, boolean singleton) {
+ super();
+ this.id = id;
+ this.version = version.toString();
+ this.versionObject = version;
+ this.singleton = singleton;
+ }
+
public TouchpointType getTouchpointType() {
return touchpointType == null ? TouchpointType.NONE : touchpointType;
}
@@ -122,10 +131,7 @@ public class InstallableUnit implements IInstallableUnitConstants, IInstallableU
public String setProperty(String key, String value) {
if (value == null)
- if (properties == null)
- return null;
- else
- return (String) properties.remove(key);
+ return (properties != null ? (String) properties.remove(key) : null);
if (properties == null)
properties = new OrderedProperties();
return (String) properties.setProperty(key, value);
@@ -169,15 +175,34 @@ public class InstallableUnit implements IInstallableUnitConstants, IInstallableU
}
public TouchpointData[] getTouchpointData() {
- return immutableTouchpointData == null ? TouchpointData.NO_TOUCHPOINT_DATA : new TouchpointData[] {immutableTouchpointData};
+ return (touchpointData == null ? TouchpointData.NO_TOUCHPOINT_DATA //
+ : (TouchpointData[]) touchpointData.toArray(new TouchpointData[touchpointData.size()]));
}
+ // TODO: resolve the schizophrenia between the singleton immutable data
+ // and the public returned touchpoint data array.
public void setImmutableTouchpointData(TouchpointData immutableData) {
- this.immutableTouchpointData = immutableData;
+ ensureTouchpointDataCapacity(4);
+ touchpointData.add(immutableData);
}
- OrderedProperties getProperties() {
- return properties == null ? NO_PROPERTIES : properties;
+ public void addTouchpointData(TouchpointData[] newData) {
+ ensureTouchpointDataCapacity(newData.length);
+ for (int i = 0; i < newData.length; i++) {
+ touchpointData.add(newData[i]);
+ }
+ }
+
+ private void ensureTouchpointDataCapacity(int size) {
+ if (touchpointData != null) {
+ touchpointData.ensureCapacity(size);
+ } else {
+ touchpointData = new ArrayList(size);
+ }
+ }
+
+ private OrderedProperties properties() {
+ return (properties != null ? properties : NO_PROPERTIES);
}
/**
@@ -186,8 +211,14 @@ public class InstallableUnit implements IInstallableUnitConstants, IInstallableU
*
* @return an <i>unmodifiable copy</i> of the IU properties.
*/
- public OrderedProperties copyProperties() {
- return (properties != null ? new UnmodifiableProperties(getProperties()) : new UnmodifiableProperties(new OrderedProperties()));
+ public OrderedProperties getProperties() {
+ return new UnmodifiableProperties(properties());
+ }
+
+ public void addProperties(OrderedProperties newProperties) {
+ if (properties == null)
+ properties = new OrderedProperties(newProperties.size());
+ properties.putAll(newProperties);
}
public boolean isFragment() {
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/InstallableUnitFragment.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/InstallableUnitFragment.java
index 49383ab34..e60f6abed 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/InstallableUnitFragment.java
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/InstallableUnitFragment.java
@@ -13,13 +13,25 @@ package org.eclipse.equinox.p2.metadata;
import org.eclipse.osgi.service.resolver.VersionRange;
import org.osgi.framework.Version;
-public class InstallableUnitFragment extends InstallableUnit implements IInstallableUnitFragment, IInstallableUnit {
- public static ProvidedCapability FRAGMENT_CAPABILITY = new ProvidedCapability(IU_KIND_NAMESPACE, "iu.fragment", new Version(1, 0, 0));
+public class InstallableUnitFragment extends InstallableUnit implements IInstallableUnitFragment {
+
+ public static ProvidedCapability FRAGMENT_CAPABILITY = new ProvidedCapability(IU_KIND_NAMESPACE, "iu.fragment", new Version(1, 0, 0)); //$NON-NLS-1$
private String hostId;
private transient VersionRange hostRangeObject;
private String hostRange;
+ public InstallableUnitFragment() {
+ super();
+ }
+
+ public InstallableUnitFragment(String id, Version version, boolean singleton, String hostId, VersionRange hostRange) {
+ super(id, version, singleton);
+ this.hostId = hostId;
+ this.hostRange = hostRange.toString();
+ hostRangeObject = hostRange;
+ }
+
public ProvidedCapability[] getProvidedCapabilities() {
ProvidedCapability[] otherCapabilities = super.getProvidedCapabilities();
if (otherCapabilities.length == 0)
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/RequiredCapability.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/RequiredCapability.java
index 7eae09c6f..48f8ac00c 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/RequiredCapability.java
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/RequiredCapability.java
@@ -26,13 +26,13 @@ import org.eclipse.osgi.service.resolver.VersionRange;
* @see InstallableUnit#IU_NAMESPACE
*/
public class RequiredCapability {
- private String filter;
- private boolean multiple;
private String name;
private String namespace;
- boolean optional;
private String range;
+ private boolean optional;
+ private boolean multiple;
+ private String filter;
private String[] selectors;
private transient VersionRange rangeObject;
@@ -73,6 +73,10 @@ public class RequiredCapability {
return filter;
}
+ public void setFilter(String filter) {
+ this.filter = filter;
+ }
+
public String getName() {
return name;
}
@@ -96,7 +100,7 @@ public class RequiredCapability {
}
public String toString() {
- return "requiredCapability: " + namespace + '/' + name + '/' + range;
+ return "requiredCapability: " + namespace + '/' + name + '/' + range; //$NON-NLS-1$
}
public int hashCode() {
@@ -155,4 +159,8 @@ public class RequiredCapability {
public String[] getSelectors() {
return selectors;
}
+
+ public void setSelectors(String[] selectors) {
+ this.selectors = selectors;
+ }
}
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/ResolvedInstallableUnit.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/ResolvedInstallableUnit.java
index 6205b90af..88b6d96d8 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/ResolvedInstallableUnit.java
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/ResolvedInstallableUnit.java
@@ -11,6 +11,7 @@ package org.eclipse.equinox.p2.metadata;
import java.util.ArrayList;
import java.util.Arrays;
import org.eclipse.equinox.internal.p2.metadata.InternalInstallableUnit;
+import org.eclipse.equinox.p2.core.helpers.OrderedProperties;
import org.osgi.framework.Version;
public class ResolvedInstallableUnit implements IResolvedInstallableUnit, InternalInstallableUnit {
@@ -57,6 +58,10 @@ public class ResolvedInstallableUnit implements IResolvedInstallableUnit, Intern
return resolved.getProperty(key);
}
+ public OrderedProperties getProperties() {
+ return resolved.getProperties();
+ }
+
public ProvidedCapability[] getProvidedCapabilities() {
ArrayList result = new ArrayList();
result.addAll(Arrays.asList(resolved.getProvidedCapabilities()));
@@ -124,7 +129,7 @@ public class ResolvedInstallableUnit implements IResolvedInstallableUnit, Intern
}
public String toString() {
- return "[R]" + resolved.toString();
+ return "[R]" + resolved.toString(); //$NON-NLS-1$
}
public IInstallableUnit getOriginal() {
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/TouchpointData.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/TouchpointData.java
index 7bfcae9e3..58c0f8590 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/TouchpointData.java
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/TouchpointData.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.equinox.p2.metadata;
+import java.util.Collections;
import java.util.Map;
public class TouchpointData {
@@ -52,4 +53,10 @@ public class TouchpointData {
public String getInstructions(String instructionKey) {
return (String) instructions.get(instructionKey);
}
+
+ // Return an unmodifiable collection of the instructions
+ // in the touchpoint data.
+ public Map getInstructions() {
+ return Collections.unmodifiableMap(instructions);
+ }
}
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/TestMetadataRepository.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/TestMetadataRepository.java
index db639f22f..ce1ca7384 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/TestMetadataRepository.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/TestMetadataRepository.java
@@ -93,4 +93,15 @@ public class TestMetadataRepository extends AbstractMetadataRepository {
units.remove(toRemove[i]);
}
}
+
+ public void initialize(RepositoryState state) {
+ this.name = state.Name;
+ this.type = state.Type;
+ this.version = state.Version.toString();
+ this.provider = state.Provider;
+ this.description = state.Description;
+ this.location = state.Location;
+ this.properties = state.Properties;
+ this.units.addAll(Arrays.asList(state.Units));
+ }
}

Back to the top