Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.virgo.kernel.artifact/src')
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/ArtifactSpecification.java64
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/bundle/BundleBridge.java221
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/ArtifactFS.java41
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/ArtifactFSEntry.java91
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/ArtifactFSFactory.java20
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/StandardArtifactFSFactory.java32
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/internal/DirectoryArtifactFS.java53
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFS.java61
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFSEntry.java124
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/internal/BundleManifestUtils.java110
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/library/LibraryBridge.java233
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/library/LibraryDefinition.java86
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/library/internal/ArtifactDescriptorLibraryDefinition.java115
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/par/ParBridge.java132
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/PlanBridge.java110
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/PlanDescriptor.java60
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/PlanReader.java162
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/internal/PlanReaderEntityResolver.java39
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/internal/PlanReaderErrorHandler.java39
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/properties/PropertiesBridge.java81
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/main/resources/org/eclipse/virgo/kernel/artifact/plan/springsource-dm-server-plan.xsd111
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/ArtifactSpecificationTests.java47
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/StubHashGenerator.java25
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/bundle/BundleBridgeTests.java192
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/bundle/StubBundleArtefactBridge.java82
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/bundle/StubRepositoryAwareArtifactDescriptor.java79
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/fs/internal/DirectoryArtifactFSTests.java31
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFSEntryTests.java41
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFSTests.java41
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/library/LibraryBridgeTests.java57
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/par/ParBridgeTests.java117
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/plan/PlanBridgeTests.java89
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/plan/PlanReaderTests.java106
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/properties/PropertiesBridgeTests.java52
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/artefacts/exploded/META-INF/MANIFEST.MF0
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/artefacts/exploded/META-INF/web/index.jsp12
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/artefacts/exploded/somefile.txt1
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/artifacts/simple.jarbin0 -> 576 bytes
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/bundle.jar/META-INF/MANIFEST.MF4
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/directories/y.different-1.2.3/META-INF/MANIFEST.MF5
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/libraries/invalid.libd3
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/libraries/test.libd4
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/pars/basic.par/META-INF/MANIFEST.MF4
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/pars/illegal-asn.par/META-INF/MANIFEST.MF4
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/pars/illegal-version.par/META-INF/MANIFEST.MF4
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-asn.par/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-description.par/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-manifest.par/META-INF/dummy.txt1
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-name.par/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-version.par/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/plans/attributes.plan15
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/plans/malformed.plan9
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/plans/multi-artifact.plan13
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/plans/properties.plan13
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/plans/single-artifact.plan11
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/properties/foo.properties1
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/wars/test.warbin0 -> 730 bytes
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/wars/testbad01.warbin0 -> 436 bytes
-rw-r--r--org.eclipse.virgo.kernel.artifact/src/test/resources/wars/testbad02.war1
59 files changed, 3061 insertions, 0 deletions
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/ArtifactSpecification.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/ArtifactSpecification.java
new file mode 100644
index 00000000..52010529
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/ArtifactSpecification.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.eclipse.virgo.util.osgi.VersionRange;
+
+/**
+ * An <code>ArtifactSpecification</code> is a reference to an artifact by type, name and version <i>range</i>.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ * Thread-safe.
+ *
+ */
+public final class ArtifactSpecification {
+
+ private final String type;
+
+ private final String name;
+
+ private final VersionRange versionRange;
+
+ private final Map<String, String> properties;
+
+ public ArtifactSpecification(String type, String name, VersionRange versionRange) {
+ this(type, name, versionRange, null);
+ }
+
+ public ArtifactSpecification(String type, String name, VersionRange versionRange, Map<String, String> properties) {
+ this.type = type;
+ this.name = name;
+ this.versionRange = versionRange;
+ this.properties = properties == null ? Collections.<String, String> emptyMap() : Collections.unmodifiableMap(properties);
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public VersionRange getVersionRange() {
+ return versionRange;
+ }
+
+ public Map<String, String> getProperties() {
+ return this.properties;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/bundle/BundleBridge.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/bundle/BundleBridge.java
new file mode 100644
index 00000000..ef28709e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/bundle/BundleBridge.java
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.bundle;
+
+import java.io.File;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.artifact.internal.BundleManifestUtils;
+import org.eclipse.virgo.repository.ArtifactBridge;
+import org.eclipse.virgo.repository.ArtifactDescriptor;
+import org.eclipse.virgo.repository.ArtifactGenerationException;
+import org.eclipse.virgo.repository.Attribute;
+import org.eclipse.virgo.repository.HashGenerator;
+import org.eclipse.virgo.repository.builder.ArtifactDescriptorBuilder;
+import org.eclipse.virgo.repository.builder.AttributeBuilder;
+import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
+import org.eclipse.virgo.util.osgi.manifest.BundleSymbolicName;
+import org.eclipse.virgo.util.osgi.manifest.ExportedPackage;
+import org.eclipse.virgo.util.osgi.manifest.FragmentHost;
+import org.eclipse.virgo.util.osgi.manifest.ImportedPackage;
+import org.eclipse.virgo.util.osgi.manifest.FragmentHost.Extension;
+
+/**
+ * Implementation of {@link ArtifactBridge} that creates an {@link ArtifactDescriptor} from an OSGi bundle packaged
+ * either as a JAR file, or a directory.
+ * <p />
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * This class is thread-safe
+ *
+ */
+public final class BundleBridge implements ArtifactBridge {
+
+ private static final String JAR_SUFFIX = ".jar";
+
+ private static final String WAR_SUFFIX = ".war";
+
+ public static final String RAW_HEADER_PREFIX = "RAW_HEADER:";
+
+ public static final String BRIDGE_TYPE = "bundle";
+
+ private final HashGenerator hashGenerator;
+
+ public BundleBridge(HashGenerator hashGenerator) {
+ this.hashGenerator = hashGenerator;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ArtifactDescriptor generateArtifactDescriptor(File artifactFile) throws ArtifactGenerationException {
+
+ if (artifactFile == null) {
+ throw new ArtifactGenerationException("The artifact file must not be null.", BRIDGE_TYPE);
+ }
+
+ BundleManifest bundleManifest;
+
+ try {
+ bundleManifest = BundleManifestUtils.readBundleManifest(artifactFile, JAR_SUFFIX, WAR_SUFFIX);
+ } catch (Exception e) {
+ throw new ArtifactGenerationException("Error occurred while parsing the manifest.", BRIDGE_TYPE, e);
+ }
+
+ if (bundleManifest == null) {
+ return null;
+ }
+
+ try {
+ ArtifactDescriptorBuilder artifactDescriptorBuilder = new ArtifactDescriptorBuilder();
+
+ String name = applyBundleSymbolicName(artifactDescriptorBuilder, bundleManifest);
+ if (name == null) { // no bundle symbolic name ==> not a bundle
+ return null;
+ }
+
+ artifactDescriptorBuilder.setUri(artifactFile.toURI());
+ artifactDescriptorBuilder.setName(name);
+ artifactDescriptorBuilder.setType(BRIDGE_TYPE);
+ artifactDescriptorBuilder.setVersion(applyBundleVersion(artifactDescriptorBuilder, bundleManifest));
+ applyImportPackage(artifactDescriptorBuilder, bundleManifest);
+ applyFragmentHost(artifactDescriptorBuilder, bundleManifest);
+ applyExportPackage(artifactDescriptorBuilder, bundleManifest);
+ this.hashGenerator.generateHash(artifactDescriptorBuilder, artifactFile);
+
+ Dictionary<String, String> rawManifest = bundleManifest.toDictionary();
+ Enumeration<String> keys = rawManifest.keys();
+
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ String value = rawManifest.get(key);
+ artifactDescriptorBuilder.addAttribute(new AttributeBuilder().setName(RAW_HEADER_PREFIX + key).setValue(value).build());
+ }
+
+ return artifactDescriptorBuilder.build();
+ } catch (Exception e) {
+ throw new ArtifactGenerationException("Manifest ill-formed.", BRIDGE_TYPE, e);
+ }
+ }
+
+ /**
+ * Providing the <code>artifactDescriptor</code> was created by this bridge in the first place then all its
+ * attributes from the main section of the manifest are placed in to a dictionary and returned. If not then
+ * <code>null</code> is returned.
+ *
+ * @param artifactDescriptor to be converted
+ * @return the new dictionary or null if the provided <code>artifactDescriptor</code> was not created by this bridge
+ */
+ public static Dictionary<String, String> convertToDictionary(ArtifactDescriptor artifactDescriptor) {
+
+ if (!BRIDGE_TYPE.equals(artifactDescriptor.getType())) {
+ return null;
+ }
+
+ Hashtable<String, String> dictionary = new Hashtable<String, String>();
+ for (Attribute attribute : artifactDescriptor.getAttributes()) {
+ if (attribute.getKey().startsWith(RAW_HEADER_PREFIX)) {
+ dictionary.put(attribute.getKey().substring(RAW_HEADER_PREFIX.length()), attribute.getValue());
+ }
+ }
+ return dictionary;
+ }
+
+ private String applyBundleSymbolicName(ArtifactDescriptorBuilder artifactBuilder, BundleManifest bundleManifest) {
+ BundleSymbolicName bundleSymbolicName = bundleManifest.getBundleSymbolicName();
+ String symbolicName = bundleSymbolicName.getSymbolicName();
+
+ if (symbolicName != null) { // not a bundle if null
+ AttributeBuilder attributeBuilder = new AttributeBuilder();
+ attributeBuilder.setName(Constants.BUNDLE_SYMBOLICNAME);
+ attributeBuilder.setValue(symbolicName);
+ attributeBuilder.putProperties(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE, bundleSymbolicName.getFragmentAttachment().name());
+ attributeBuilder.putProperties(Constants.SINGLETON_DIRECTIVE, Boolean.toString(bundleSymbolicName.isSingleton()));
+ artifactBuilder.addAttribute(attributeBuilder.build());
+ }
+ return symbolicName;
+ }
+
+ private Version applyBundleVersion(ArtifactDescriptorBuilder artifactBuilder, BundleManifest bundleManifest) {
+ Version version = bundleManifest.getBundleVersion();
+ artifactBuilder.addAttribute(new AttributeBuilder().setName(Constants.BUNDLE_VERSION).setValue(version.toString()).build());
+ return version;
+ }
+
+ private void applyImportPackage(ArtifactDescriptorBuilder artifactBuilder, BundleManifest bundleManifest) {
+ for (ImportedPackage importedPackage : bundleManifest.getImportPackage().getImportedPackages()) {
+ AttributeBuilder attributeBuilder = new AttributeBuilder();
+ attributeBuilder.setName(Constants.IMPORT_PACKAGE);
+ attributeBuilder.setValue(importedPackage.getPackageName());
+ attributeBuilder.putProperties(Constants.RESOLUTION_DIRECTIVE, importedPackage.getResolution().name());
+ attributeBuilder.putProperties(Constants.VERSION_ATTRIBUTE, importedPackage.getVersion().toParseString());
+ artifactBuilder.addAttribute(attributeBuilder.build());
+ }
+ }
+
+ private void applyFragmentHost(ArtifactDescriptorBuilder artifactBuilder, BundleManifest bundleManifest) {
+ FragmentHost fragmentHost = bundleManifest.getFragmentHost();
+ String hostSymbolicName = fragmentHost.getBundleSymbolicName();
+
+ if (hostSymbolicName != null) {
+ AttributeBuilder attributeBuilder = new AttributeBuilder();
+ attributeBuilder.setName(Constants.FRAGMENT_HOST);
+ attributeBuilder.setValue(hostSymbolicName);
+
+ Extension extension = fragmentHost.getExtension();
+ if (extension != null) {
+ attributeBuilder.putProperties(Constants.EXTENSION_DIRECTIVE, extension.name());
+ }
+
+ attributeBuilder.putProperties(Constants.BUNDLE_VERSION_ATTRIBUTE, fragmentHost.getBundleVersion().toParseString());
+ artifactBuilder.addAttribute(attributeBuilder.build());
+ }
+ }
+
+ private void applyExportPackage(ArtifactDescriptorBuilder artifactBuilder, BundleManifest bundleManifest) {
+ for (ExportedPackage exportedPackage : bundleManifest.getExportPackage().getExportedPackages()) {
+ AttributeBuilder attributeBuilder = new AttributeBuilder();
+ attributeBuilder.setName(Constants.EXPORT_PACKAGE);
+ attributeBuilder.setValue(exportedPackage.getPackageName());
+
+ attributeBuilder.putProperties(Constants.VERSION_ATTRIBUTE, exportedPackage.getVersion().toString());
+
+ List<String> include = exportedPackage.getInclude();
+ if (include.size() > 0) {
+ attributeBuilder.putProperties(Constants.INCLUDE_DIRECTIVE, include);
+ }
+
+ List<String> exclude = exportedPackage.getExclude();
+ if (exclude.size() > 0) {
+ attributeBuilder.putProperties(Constants.EXCLUDE_DIRECTIVE, exclude);
+ }
+
+ List<String> mandatory = exportedPackage.getMandatory();
+ if (mandatory.size() > 0) {
+ attributeBuilder.putProperties(Constants.MANDATORY_DIRECTIVE, mandatory);
+ }
+ List<String> uses = exportedPackage.getUses();
+ if (uses.size() > 0) {
+ attributeBuilder.putProperties(Constants.USES_DIRECTIVE, uses);
+ }
+
+ artifactBuilder.addAttribute(attributeBuilder.build());
+ }
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/ArtifactFS.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/ArtifactFS.java
new file mode 100644
index 00000000..5b347617
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/ArtifactFS.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.fs;
+
+import java.io.File;
+
+/**
+ * An abstraction that represents the filesystem location of an artifact
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations must be threadsafe
+ *
+ */
+public interface ArtifactFS {
+
+ /**
+ * Gets an entry from this artifact
+ *
+ * @param name The name of the entry to retrieve
+ * @return An {@link ArtifactFSEntry} that represents the entry in the artifact
+ */
+ ArtifactFSEntry getEntry(String name);
+
+ /**
+ * Gets the file upon which this {@link ArtifactFS} is built
+ *
+ * @return the underlying file for this {@link ArtifactFS}
+ */
+ File getFile();
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/ArtifactFSEntry.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/ArtifactFSEntry.java
new file mode 100644
index 00000000..5682d000
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/ArtifactFSEntry.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.fs;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * An abstraction that represents an entry inside of an artifact
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe
+ *
+ * @see ArtifactFS
+ */
+public interface ArtifactFSEntry {
+
+ /**
+ * Gets the path of this entry, relative to the root {@link ArtifactFS}
+ *
+ * @return the path of this entry
+ */
+ String getPath();
+
+ /**
+ * Gets the name of this entry
+ *
+ * @return the name of this entry
+ */
+ String getName();
+
+ /**
+ * Deletes this entry from the artifact
+ *
+ * @return whether the deletion of this artifact was successful
+ */
+ boolean delete();
+
+ /**
+ * Whether this entry is a directory
+ *
+ * @return whether this entry is a directory
+ */
+ boolean isDirectory();
+
+ /**
+ * Gets an {@link InputStream} for reading from this artifact. This method is not supported for directory artifacts.
+ *
+ * @return an {@link InputStream} for reading from this artifact
+ */
+ InputStream getInputStream();
+
+ /**
+ * Gets an {@link OutputStream} for writing to this artifact. The artifact is created if it does not already exist
+ * and is overwritten if it does. This method is not supported for directory artifacts.
+ *
+ * @return an {@link OutputStream} for writing to this artifact
+ */
+ OutputStream getOutputStream();
+
+ /**
+ * Returns a list of children entries for this entry. This method is only supported for directory artifacts.
+ *
+ * @return a list of children entries.
+ */
+ ArtifactFSEntry[] getChildren();
+
+ /**
+ * Returns a new {@link ArtifactFS} that is rooted at this entry
+ *
+ * @return a new {@link ArtifactFS}
+ */
+ ArtifactFS getArtifactFS();
+
+ /**
+ * Returns <code>true</code> if this entry exists, otherwise <code>false</code>
+ * @return <code>true</code> if this entry exists, otherwise <code>false</code>
+ */
+ boolean exists();
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/ArtifactFSFactory.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/ArtifactFSFactory.java
new file mode 100644
index 00000000..7adf151a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/ArtifactFSFactory.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.fs;
+
+import java.io.File;
+
+public interface ArtifactFSFactory {
+
+ public abstract ArtifactFS create(File file);
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/StandardArtifactFSFactory.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/StandardArtifactFSFactory.java
new file mode 100644
index 00000000..7c72be84
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/StandardArtifactFSFactory.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.fs;
+
+import java.io.File;
+
+import org.eclipse.virgo.kernel.artifact.fs.internal.DirectoryArtifactFS;
+import org.eclipse.virgo.kernel.artifact.fs.internal.FileArtifactFS;
+
+
+public final class StandardArtifactFSFactory implements ArtifactFSFactory {
+
+ /**
+ * {@inheritDoc}
+ */
+ public ArtifactFS create(File file) {
+ if (file.isDirectory()) {
+ return new DirectoryArtifactFS(file);
+ }
+ return new FileArtifactFS(file);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/internal/DirectoryArtifactFS.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/internal/DirectoryArtifactFS.java
new file mode 100644
index 00000000..15c19733
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/internal/DirectoryArtifactFS.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.fs.internal;
+
+import java.io.File;
+
+import org.eclipse.virgo.kernel.artifact.fs.ArtifactFS;
+import org.eclipse.virgo.kernel.artifact.fs.ArtifactFSEntry;
+
+
+/**
+ * An implementation of {@link ArtifactFS} that represents a directory on the filesystem
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe
+ *
+ */
+public final class DirectoryArtifactFS implements ArtifactFS {
+
+ private final File root;
+
+ public DirectoryArtifactFS(File root) {
+ if (root.exists() && !root.isDirectory()) {
+ throw new IllegalArgumentException(String.format("File '%s' must be a directory", root.getAbsolutePath()));
+ }
+ this.root = root;
+ }
+
+ public ArtifactFSEntry getEntry(String name) {
+ return new FileArtifactFSEntry(this.root, new File(root, name));
+ }
+
+ public File getFile() {
+ return this.root;
+ }
+
+ @Override
+ public String toString() {
+ return this.root.getAbsolutePath();
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFS.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFS.java
new file mode 100644
index 00000000..5363753c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFS.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.fs.internal;
+
+import java.io.File;
+
+import org.eclipse.virgo.kernel.artifact.fs.ArtifactFS;
+import org.eclipse.virgo.kernel.artifact.fs.ArtifactFSEntry;
+import org.eclipse.virgo.util.common.StringUtils;
+
+/**
+ * An implementation of {@link ArtifactFS} that represents a single file. This implementation will only allow a call to
+ * {@link #getEntry(String)} with a <code>null</code> value. A call with this argument returns an entry that matches
+ * this single element.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe
+ *
+ */
+public class FileArtifactFS implements ArtifactFS {
+
+ private final File file;
+
+ public FileArtifactFS(File file) {
+ if (file.isDirectory()) {
+ throw new IllegalArgumentException(String.format("This ArtifactFS cannot be created for '%s' as it is a directory",
+ file.getAbsolutePath()));
+ }
+ this.file = file;
+ }
+
+ public ArtifactFSEntry getEntry(String name) {
+ if (StringUtils.hasText(name)) {
+ throw new IllegalArgumentException(
+ "This ArtifactFS represents a single static file. Requesting any entry other than null or \"\" is unsupported");
+ }
+
+ return new FileArtifactFSEntry(this.file.getParentFile(), this.file);
+ }
+
+ public File getFile() {
+ return this.file;
+ }
+
+ @Override
+ public String toString() {
+ return this.file.getAbsolutePath();
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFSEntry.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFSEntry.java
new file mode 100644
index 00000000..ace1b3e4
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFSEntry.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.fs.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.artifact.fs.ArtifactFS;
+import org.eclipse.virgo.kernel.artifact.fs.ArtifactFSEntry;
+import org.eclipse.virgo.kernel.artifact.fs.ArtifactFSFactory;
+import org.eclipse.virgo.kernel.artifact.fs.StandardArtifactFSFactory;
+import org.eclipse.virgo.util.io.PathReference;
+
+final class FileArtifactFSEntry implements ArtifactFSEntry {
+
+ private final ArtifactFSFactory artifactFSFactory = new StandardArtifactFSFactory();
+
+ private final File root;
+
+ private final File file;
+
+ public FileArtifactFSEntry(File root, File file) {
+ this.root = root;
+ this.file = file;
+ }
+
+ public boolean delete() {
+ return new PathReference(this.file).delete(true);
+ }
+
+ public ArtifactFSEntry[] getChildren() {
+ List<ArtifactFSEntry> children = new ArrayList<ArtifactFSEntry>();
+ File[] files = this.file.listFiles();
+ if (files != null) {
+ for (File child : files) {
+ children.add(new FileArtifactFSEntry(this.root, child));
+ }
+ }
+ return children.toArray(new ArtifactFSEntry[children.size()]);
+ }
+
+ public InputStream getInputStream() {
+ if (!this.file.exists()) {
+ throw new UnsupportedOperationException(String.format("Cannot open an input stream for '%s' as it does not exist",
+ this.file.getAbsolutePath()));
+ }
+
+ if (this.file.isDirectory()) {
+ throw new UnsupportedOperationException(String.format("Cannot open an input stream for '%s' as it is a directory",
+ this.file.getAbsolutePath()));
+ }
+
+ try {
+ return new FileInputStream(this.file);
+ } catch (FileNotFoundException e) {
+ throw new IllegalStateException(String.format("Unable to open an input stream for '%s'", this.file.getAbsolutePath()), e);
+ }
+ }
+
+ public String getPath() {
+ String relativePath = this.file.getAbsolutePath().substring(this.root.getAbsolutePath().length());
+ if (relativePath.startsWith("/") || relativePath.startsWith("\\")) {
+ return relativePath.substring(1);
+ }
+ return relativePath;
+
+ }
+
+ public String getName() {
+ return this.file.getName();
+ }
+
+ public OutputStream getOutputStream() {
+ if (this.file.exists()) {
+ if (this.file.isDirectory()) {
+ throw new UnsupportedOperationException(String.format("Cannot open an ouput stream for '%s' as it is a directory",
+ this.file.getAbsolutePath()));
+ }
+ } else {
+ File parentDir = this.file.getParentFile();
+ if (!parentDir.exists() && !parentDir.mkdirs()) {
+ throw new IllegalStateException("Failed to create directory " + parentDir + " prior to creating stream for " + this.file);
+ }
+ }
+
+ try {
+ return new FileOutputStream(this.file);
+ } catch (FileNotFoundException e) {
+ throw new IllegalStateException(String.format("Unable to open an output stream for '%s'", this.file.getAbsolutePath()), e);
+ }
+ }
+
+ public boolean isDirectory() {
+ return this.file.isDirectory();
+ }
+
+ public String toString() {
+ return this.file.getAbsolutePath();
+ }
+
+ public ArtifactFS getArtifactFS() {
+ return this.artifactFSFactory.create(this.file);
+ }
+
+ public boolean exists() {
+ return this.file.exists();
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/internal/BundleManifestUtils.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/internal/BundleManifestUtils.java
new file mode 100644
index 00000000..da2b22f5
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/internal/BundleManifestUtils.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.eclipse.virgo.util.io.FileCopyUtils;
+import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
+import org.eclipse.virgo.util.osgi.manifest.BundleManifestFactory;
+
+
+/**
+ * Utility methods for working with {@link BundleManifest BundleManifests}.
+
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+public final class BundleManifestUtils {
+
+ /**
+ * Reads the <code>BundleManifest</code> from the supplied <code>file</code>. The <code>File</code> can either
+ * be a file, i.e. a jar archive, or a directory. If the file is an archive its manifest will only be read
+ * if its name ends with one of the supplied <code>archiveSuffixes</code>
+ *
+ * @param file The file from which the manifest is to be read.
+ * @param archiveSuffixes The suffixes with which an archive's file name must end
+ * @return The <code>BundleManifest</code> from the file or <code>null</code> if one was not found.
+ * @throws IOException Thrown if a manifest is detected but the reading of it fails.
+ */
+ public static BundleManifest readBundleManifest(File file, String... archiveSuffixes) throws IOException {
+ String fileName = file.getName();
+
+ Reader reader = null;
+
+ if (file.isDirectory()) {
+ File manifestFile = new File(file, JarFile.MANIFEST_NAME);
+ if (manifestFile.exists()) {
+ reader = manifestReaderFromFile(manifestFile);
+ }
+ } else {
+ for (String suffix : archiveSuffixes) {
+ if (fileName.endsWith(suffix)) {
+ reader = manifestReaderFromJar(file);
+ }
+ }
+ }
+
+ if (reader != null) {
+ return BundleManifestFactory.createBundleManifest(reader);
+ } else {
+ return null;
+ }
+ }
+
+ private static Reader manifestReaderFromJar(File file) throws IOException {
+ JarFile jar = null;
+ try {
+ jar = new JarFile(file);
+ JarEntry entry = jar.getJarEntry(JarFile.MANIFEST_NAME);
+
+ if (entry == null) {
+ return null; // not an error -- no manifest means this isn't a bundle
+ }
+ StringWriter writer = new StringWriter();
+ FileCopyUtils.copy(new InputStreamReader(jar.getInputStream(entry)), writer);
+ return new StringReader(writer.toString());
+ } catch (Exception e) {
+ throw new IOException(String.format("Failed to read manifest from file '%s'.", file.getName()), e);
+ } finally {
+ if (jar != null) {
+ try {
+ jar.close();
+ } catch (IOException ioe) {
+ throw new IOException(String.format("Failed to close file '%s'.", file.getName()), ioe);
+ }
+ }
+ }
+ }
+
+ private static Reader manifestReaderFromFile(File file) throws IOException {
+ try {
+ StringWriter writer = new StringWriter();
+ FileCopyUtils.copy(new InputStreamReader(new FileInputStream(file)), writer);
+ return new StringReader(writer.toString());
+ } catch (IOException ioe) {
+ throw new IOException("Failed to create reader for manifest file.", ioe);
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/library/LibraryBridge.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/library/LibraryBridge.java
new file mode 100644
index 00000000..c50002df
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/library/LibraryBridge.java
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.library;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map.Entry;
+
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.artifact.library.LibraryDefinition.Sharing;
+import org.eclipse.virgo.kernel.artifact.library.internal.ArtifactDescriptorLibraryDefinition;
+import org.eclipse.virgo.repository.ArtifactBridge;
+import org.eclipse.virgo.repository.ArtifactDescriptor;
+import org.eclipse.virgo.repository.ArtifactGenerationException;
+import org.eclipse.virgo.repository.HashGenerator;
+import org.eclipse.virgo.repository.builder.ArtifactDescriptorBuilder;
+import org.eclipse.virgo.repository.builder.AttributeBuilder;
+import org.eclipse.virgo.util.common.CaseInsensitiveMap;
+import org.eclipse.virgo.util.common.StringUtils;
+import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
+import org.eclipse.virgo.util.osgi.manifest.BundleManifestFactory;
+import org.eclipse.virgo.util.osgi.manifest.ImportedBundle;
+import org.eclipse.virgo.util.osgi.manifest.parse.HeaderDeclaration;
+import org.eclipse.virgo.util.osgi.manifest.parse.HeaderParserFactory;
+import org.eclipse.virgo.util.parser.manifest.ManifestContents;
+import org.eclipse.virgo.util.parser.manifest.ManifestParser;
+import org.eclipse.virgo.util.parser.manifest.RecoveringManifestParser;
+
+public class LibraryBridge implements ArtifactBridge {
+
+ public static final String LIBRARY_VERSION = "Library-Version";
+
+ public static final String LIBRARY_SYMBOLICNAME = "Library-SymbolicName";
+
+ public static final String IMPORT_BUNDLE = "Import-Bundle";
+
+ public static final String LIBRARY_NAME = "Library-Name";
+
+ public static final String LIBRARY_DESCRIPTION = "Library-Description";
+
+ private static final String LIBRARY_DESCRIPTOR_SUFFIX = ".libd";
+
+ private static final String DEFAULT_LIBRARY_VERSION = "0";
+
+ public static final String RAW_HEADER_PREFIX = "RAW_HEADER:";
+
+ public static final String SHARING_DIRECTIVE = "sharing";
+
+ private static final String VERSION_ATTRIBUTE = "version";
+
+ private static final String RESOLUTION_DIRECTIVE = "resolution";
+
+ private static final String IMPORT_SCOPE_DIRECTIVE = "import-scope";
+
+ private final HashGenerator hashGenerator;
+
+ public LibraryBridge(HashGenerator hashGenerator) {
+ this.hashGenerator = hashGenerator;
+ }
+
+ public ArtifactDescriptor generateArtifactDescriptor(File artifactFile) throws ArtifactGenerationException {
+
+ if (!artifactFile.getName().endsWith(LIBRARY_DESCRIPTOR_SUFFIX)) {
+ return null;
+ }
+
+ ManifestContents manifestContents;
+
+ try {
+ manifestContents = getManifestContents(artifactFile);
+ } catch (IOException ie) {
+ throw new ArtifactGenerationException("Unable to read library definition", LibraryDefinition.LIBRARY_TYPE, ie);
+ }
+
+ CaseInsensitiveMap<String> contentsMap = new CaseInsensitiveMap<String>();
+ contentsMap.putAll(manifestContents.getMainAttributes());
+
+ ArtifactDescriptorBuilder builder = new ArtifactDescriptorBuilder();
+ builder.setUri(artifactFile.toURI());
+ builder.setType(LibraryDefinition.LIBRARY_TYPE);
+
+ String name = createAttributeFromLibrarySymbolicName(contentsMap, artifactFile, builder);
+ builder.setName(name);
+
+ Version version = createAttributeFromLibraryVersion(contentsMap, builder);
+ builder.setVersion(version);
+
+ createAttributesFromImportBundle(contentsMap, artifactFile, builder);
+ createAttributeFromLibraryName(contentsMap, builder);
+ createAttributeFromLibraryDescription(contentsMap, builder);
+
+ createAttributesFromRawHeaders(contentsMap, builder);
+
+ this.hashGenerator.generateHash(builder, artifactFile);
+
+ return builder.build();
+ }
+
+ private static ManifestContents getManifestContents(File file) throws IOException {
+ ManifestParser manifestParser = new RecoveringManifestParser();
+
+ Reader reader = null;
+
+ try {
+ reader = new FileReader(file);
+ return manifestParser.parse(reader);
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+ }
+
+ private static String createAttributeFromLibrarySymbolicName(CaseInsensitiveMap<String> manifestAttributes, File artifact,
+ ArtifactDescriptorBuilder builder) throws ArtifactGenerationException {
+ String symbolicNameString = getRequiredHeader(LIBRARY_SYMBOLICNAME, manifestAttributes, artifact);
+ HeaderDeclaration symbolicNameDeclaration = HeaderParserFactory.newHeaderParser(null).parseLibrarySymbolicName(symbolicNameString);
+
+ String symbolicName = symbolicNameDeclaration.getNames().get(0);
+
+ Sharing sharing;
+
+ String sharingString = symbolicNameDeclaration.getDirectives().get(SHARING_DIRECTIVE);
+ if (sharingString != null) {
+ sharing = Sharing.valueOf(sharingString.toUpperCase(Locale.ENGLISH));
+ } else {
+ sharing = Sharing.SHAREABLE;
+ }
+
+ AttributeBuilder attBuilder = new AttributeBuilder();
+ attBuilder.setName(LIBRARY_SYMBOLICNAME);
+ attBuilder.setValue(symbolicName);
+ attBuilder.putProperties(SHARING_DIRECTIVE, sharing.toString().toLowerCase(Locale.ENGLISH));
+
+ builder.addAttribute(attBuilder.build());
+ return symbolicName;
+ }
+
+ private static Version createAttributeFromLibraryVersion(CaseInsensitiveMap<String> manifestAttributes, ArtifactDescriptorBuilder builder) {
+ String versionString = manifestAttributes.get(LIBRARY_VERSION);
+
+ if (!StringUtils.hasText(versionString)) {
+ versionString = DEFAULT_LIBRARY_VERSION;
+ }
+
+ Version version = new Version(versionString);
+
+ builder.addAttribute(new AttributeBuilder().setName(LIBRARY_VERSION).setValue(version.toString()).build());
+ return version;
+ }
+
+ private static void createAttributesFromImportBundle(CaseInsensitiveMap<String> manifestAttributes, File artifact,
+ ArtifactDescriptorBuilder builder) throws ArtifactGenerationException {
+ String importBundleString = getRequiredHeader(IMPORT_BUNDLE, manifestAttributes, artifact);
+ Dictionary<String, String> headers = new Hashtable<String, String>();
+ headers.put(IMPORT_BUNDLE, importBundleString);
+ BundleManifest manifest = BundleManifestFactory.createBundleManifest(headers);
+
+ List<ImportedBundle> importedBundles = manifest.getImportBundle().getImportedBundles();
+
+ for (ImportedBundle importedBundle : importedBundles) {
+ AttributeBuilder attBuilder = new AttributeBuilder();
+ attBuilder.setName(IMPORT_BUNDLE);
+ attBuilder.setValue(importedBundle.getBundleSymbolicName());
+
+ attBuilder.putProperties(RESOLUTION_DIRECTIVE, importedBundle.getResolution().toString().toLowerCase(Locale.ENGLISH));
+ attBuilder.putProperties(VERSION_ATTRIBUTE, importedBundle.getVersion().toParseString());
+ if (importedBundle.isApplicationImportScope()) {
+ attBuilder.putProperties(IMPORT_SCOPE_DIRECTIVE, "application");
+ }
+ attBuilder.putProperties(SHARING_DIRECTIVE, importedBundle.getSharing().toString().toLowerCase(Locale.ENGLISH));
+
+ builder.addAttribute(attBuilder.build());
+ }
+ }
+
+ private static void createAttributeFromLibraryName(CaseInsensitiveMap<String> manifestAttributes, ArtifactDescriptorBuilder builder) {
+ String name = manifestAttributes.get(LIBRARY_NAME);
+ if (name != null) {
+ builder.addAttribute(new AttributeBuilder().setName(LIBRARY_NAME).setValue(name).build());
+ }
+ }
+
+ private static void createAttributeFromLibraryDescription(CaseInsensitiveMap<String> manifestAttributes, ArtifactDescriptorBuilder builder) {
+ String name = manifestAttributes.get(LIBRARY_DESCRIPTION);
+ if (name != null) {
+ builder.addAttribute(new AttributeBuilder().setName(LIBRARY_DESCRIPTION).setValue(name).build());
+ }
+ }
+
+ private static void createAttributesFromRawHeaders(CaseInsensitiveMap<String> manifestAttributes, ArtifactDescriptorBuilder builder) {
+ for (Entry<String, String> entry : manifestAttributes.entrySet()) {
+ builder.addAttribute(new AttributeBuilder().setName(RAW_HEADER_PREFIX + entry.getKey()).setValue(entry.getValue()).build());
+ }
+ }
+
+ private static String getRequiredHeader(String name, CaseInsensitiveMap<String> attrs, File artifactFile) throws ArtifactGenerationException {
+ String value = attrs.get(name);
+ if (value == null || value.trim().length() == 0) {
+ throw new ArtifactGenerationException(String.format("Required attribute '%s' is missing from library descriptor '%s'.", name,
+ artifactFile.getName()), LibraryDefinition.LIBRARY_TYPE);
+ }
+ return value;
+ }
+
+ public static List<ImportedBundle> parseImportBundle(String importBundleString) {
+ Dictionary<String, String> headers = new Hashtable<String, String>();
+ headers.put(IMPORT_BUNDLE, importBundleString);
+ BundleManifest manifest = BundleManifestFactory.createBundleManifest(headers);
+ return manifest.getImportBundle().getImportedBundles();
+ }
+
+ public static LibraryDefinition createLibraryDefinition(ArtifactDescriptor artefact) {
+ return new ArtifactDescriptorLibraryDefinition(artefact);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/library/LibraryDefinition.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/library/LibraryDefinition.java
new file mode 100644
index 00000000..d4bbad18
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/library/LibraryDefinition.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.library;
+
+import java.net.URI;
+import java.util.List;
+
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.util.osgi.manifest.ImportedBundle;
+
+/**
+ * Defines a library that can be installed into the OSGi framework. <p/>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations must be threadsafe.
+ *
+ */
+public interface LibraryDefinition {
+
+ public static final String LIBRARY_TYPE = "library";
+
+ enum Sharing {
+ SHAREABLE, NON_SHAREABLE
+ }
+
+ /**
+ * Gets the symbolic name of the library.
+ *
+ * @return the library's symbolic name
+ */
+ String getSymbolicName();
+
+ /**
+ * Gets the description of the library. <p/>
+ *
+ * May return <code>null</code> if no description is defined.
+ *
+ * @return the library's description
+ */
+ String getDescription();
+
+ /**
+ * Gets the name of the library.
+ *
+ * @return the library's name.
+ */
+ String getName();
+
+ /**
+ * Gets the version of the library.
+ *
+ * @return the library's version.
+ */
+ Version getVersion();
+
+ /**
+ * Gets the sharing setting of the library.
+ *
+ * @return the sharing setting.
+ */
+ Sharing getSharing();
+
+ /**
+ * Gets the bundles in this library.
+ *
+ * @return the library's bundles.
+ */
+ List<ImportedBundle> getLibraryBundles();
+
+ /**
+ * Returns the location of the library
+ * @return the library's location
+ */
+ URI getLocation();
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/library/internal/ArtifactDescriptorLibraryDefinition.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/library/internal/ArtifactDescriptorLibraryDefinition.java
new file mode 100644
index 00000000..fedb9bb2
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/library/internal/ArtifactDescriptorLibraryDefinition.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.library.internal;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.artifact.library.LibraryBridge;
+import org.eclipse.virgo.kernel.artifact.library.LibraryDefinition;
+import org.eclipse.virgo.repository.ArtifactDescriptor;
+import org.eclipse.virgo.repository.Attribute;
+import org.eclipse.virgo.util.osgi.manifest.ImportedBundle;
+
+public final class ArtifactDescriptorLibraryDefinition implements LibraryDefinition {
+
+ private final String description;
+
+ private final String name;
+
+ private final URI location;
+
+ private final Version version;
+
+ private final String symbolicName;
+
+ private final Sharing sharing;
+
+ private final List<ImportedBundle> importedBundles;
+
+ public ArtifactDescriptorLibraryDefinition(ArtifactDescriptor artifactDescriptor) {
+ Set<Attribute> descriptionSet = artifactDescriptor.getAttribute(LibraryBridge.LIBRARY_DESCRIPTION);
+ if (!descriptionSet.isEmpty()) {
+ this.description = descriptionSet.iterator().next().getValue();
+ } else {
+ this.description = null;
+ }
+
+ Set<Attribute> nameSet = artifactDescriptor.getAttribute(LibraryBridge.LIBRARY_NAME);
+ if (!nameSet.isEmpty()) {
+ this.name = nameSet.iterator().next().getValue();
+ } else {
+ this.name = null;
+ }
+
+ this.location = artifactDescriptor.getUri();
+
+ Set<Attribute> versionSet = artifactDescriptor.getAttribute(LibraryBridge.LIBRARY_VERSION);
+ this.version = new Version(versionSet.iterator().next().getValue());
+
+ Set<Attribute> symbolicNameSet = artifactDescriptor.getAttribute(LibraryBridge.LIBRARY_SYMBOLICNAME);
+ Attribute symbolicNameAttribute = symbolicNameSet.iterator().next();
+
+ this.symbolicName = symbolicNameAttribute.getValue();
+
+ Map<String, Set<String>> symbolicNameProperties = symbolicNameAttribute.getProperties();
+
+ Sharing sharing = Sharing.SHAREABLE;
+
+ for (Entry<String, Set<String>> property : symbolicNameProperties.entrySet()) {
+ if (LibraryBridge.SHARING_DIRECTIVE.equals(property.getKey())) {
+ sharing = Sharing.valueOf(property.getValue().iterator().next().toUpperCase(Locale.ENGLISH));
+ break;
+ }
+ }
+
+ this.sharing = sharing;
+
+ String importBundleHeader = artifactDescriptor.getAttribute(LibraryBridge.RAW_HEADER_PREFIX + LibraryBridge.IMPORT_BUNDLE).iterator().next().getValue();
+
+ this.importedBundles = LibraryBridge.parseImportBundle(importBundleHeader);
+ }
+
+ public String getDescription() {
+ return this.description;
+ }
+
+ public List<ImportedBundle> getLibraryBundles() {
+ return this.importedBundles;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public Sharing getSharing() {
+ return this.sharing;
+ }
+
+ public String getSymbolicName() {
+ return this.symbolicName;
+ }
+
+ public Version getVersion() {
+ return this.version;
+ }
+
+ public URI getLocation() {
+ return this.location;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/par/ParBridge.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/par/ParBridge.java
new file mode 100644
index 00000000..0219e9cc
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/par/ParBridge.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.par;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.artifact.internal.BundleManifestUtils;
+import org.eclipse.virgo.repository.ArtifactBridge;
+import org.eclipse.virgo.repository.ArtifactDescriptor;
+import org.eclipse.virgo.repository.ArtifactGenerationException;
+import org.eclipse.virgo.repository.HashGenerator;
+import org.eclipse.virgo.repository.builder.ArtifactDescriptorBuilder;
+import org.eclipse.virgo.repository.builder.AttributeBuilder;
+import org.eclipse.virgo.util.common.StringUtils;
+import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
+
+/**
+ * An <code>ArtifactBridge</code> for PAR files.
+ *
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+public final class ParBridge implements ArtifactBridge {
+
+ private static final String SYMBOLIC_NAME_REGEX = "[-_0-9a-zA-Z]+(\\.[-_0-9a-zA-Z]+)*";
+
+ private static final String HEADER_APPLICATION_SYMBOLIC_NAME = "Application-SymbolicName";
+
+ private static final String HEADER_APPLICATION_NAME = "Application-Name";
+
+ private static final String HEADER_APPLICATION_DESCRIPTION = "Application-Description";
+
+ private static final String HEADER_APPLICATION_VERSION = "Application-Version";
+
+ public static final String BRIDGE_TYPE = "par";
+
+ private final HashGenerator hashGenerator;
+
+ public ParBridge(HashGenerator hashGenerator) {
+ this.hashGenerator = hashGenerator;
+ }
+
+ public ArtifactDescriptor generateArtifactDescriptor(File artifactFile) throws ArtifactGenerationException {
+
+ BundleManifest manifest;
+
+ try {
+ manifest = BundleManifestUtils.readBundleManifest(artifactFile, ".par");
+ } catch (IOException ioe) {
+ throw new ArtifactGenerationException("Failed to read manifest from " + artifactFile, ioe);
+ }
+
+ if (manifest != null) {
+ return createDescriptorFromManifest(manifest, artifactFile);
+ } else {
+ return null;
+ }
+ }
+
+ private ArtifactDescriptor createDescriptorFromManifest(BundleManifest manifest, File artifactFile) throws ArtifactGenerationException {
+
+ String symbolicName = getApplicationSymbolicName(manifest);
+
+ if (symbolicName == null) {
+ return null;
+ }
+
+ Version version = getApplicationVersion(manifest);
+
+ ArtifactDescriptorBuilder builder = new ArtifactDescriptorBuilder();
+ builder.setType(BRIDGE_TYPE).setName(symbolicName).setVersion(version).setUri(artifactFile.toURI());
+
+ applyAttributeIfPresent(HEADER_APPLICATION_NAME, manifest, builder);
+ applyAttributeIfPresent(HEADER_APPLICATION_DESCRIPTION, manifest, builder);
+
+ this.hashGenerator.generateHash(builder, artifactFile);
+
+ return builder.build();
+ }
+
+ private void applyAttributeIfPresent(String headerName, BundleManifest manifest, ArtifactDescriptorBuilder builder) {
+ String headerValue = manifest.getHeader(headerName);
+ if (headerValue != null) {
+ AttributeBuilder attributeBuilder = new AttributeBuilder();
+ builder.addAttribute(attributeBuilder.setName(headerName).setValue(headerValue).build());
+ }
+ }
+
+ private Version getApplicationVersion(BundleManifest manifest) throws ArtifactGenerationException {
+ String versionString = manifest.getHeader(HEADER_APPLICATION_VERSION);
+ Version version;
+
+ if (!StringUtils.hasText(versionString)) {
+ version = Version.emptyVersion;
+ } else {
+ try {
+ version = new Version(versionString);
+ } catch (IllegalArgumentException iae) {
+ throw new ArtifactGenerationException("Version '" + versionString + "' is ill-formed", iae);
+ }
+ }
+ return version;
+ }
+
+ private String getApplicationSymbolicName(BundleManifest manifest) throws ArtifactGenerationException {
+ String symbolicName = manifest.getHeader(HEADER_APPLICATION_SYMBOLIC_NAME);
+
+ if (!StringUtils.hasText(symbolicName)) {
+ return null;
+ }
+ if (!symbolicName.matches(SYMBOLIC_NAME_REGEX)) {
+ throw new ArtifactGenerationException(HEADER_APPLICATION_SYMBOLIC_NAME + " '" + symbolicName + "' contains illegal characters");
+ }
+ return symbolicName;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/PlanBridge.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/PlanBridge.java
new file mode 100644
index 00000000..4eeab40f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/PlanBridge.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.plan;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.artifact.ArtifactSpecification;
+import org.eclipse.virgo.repository.ArtifactBridge;
+import org.eclipse.virgo.repository.ArtifactDescriptor;
+import org.eclipse.virgo.repository.ArtifactGenerationException;
+import org.eclipse.virgo.repository.HashGenerator;
+import org.eclipse.virgo.repository.builder.ArtifactDescriptorBuilder;
+import org.eclipse.virgo.repository.builder.AttributeBuilder;
+import org.eclipse.virgo.util.io.IOUtils;
+
+/**
+ * An {@link ArtifactBridge} that reads and parses a .plan file.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe
+ *
+ */
+public class PlanBridge implements ArtifactBridge {
+
+ public static final String BRIDGE_TYPE = "plan";
+
+ private final PlanReader reader = new PlanReader();
+
+ private static final String SCOPED = "scoped";
+
+ private static final String ATOMIC = "atomic";
+
+ private static final String ARTIFACT = "artifact";
+
+ private static final String TYPE = "type";
+
+ private static final String NAME = "name";
+
+ private static final String VERSION = "version";
+
+ private final HashGenerator hashGenerator;
+
+ public PlanBridge(HashGenerator hashGenerator) {
+ this.hashGenerator = hashGenerator;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ArtifactDescriptor generateArtifactDescriptor(File artifactFile) throws ArtifactGenerationException {
+ if (!artifactFile.getPath().endsWith(".plan")) {
+ return null;
+ }
+
+ PlanDescriptor plan;
+ FileInputStream in = null;
+ try {
+ in = new FileInputStream(artifactFile);
+ plan = reader.read(in);
+ } catch (Exception e) {
+ throw new ArtifactGenerationException("Failed to read plan descriptor", BRIDGE_TYPE, e);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+
+ return parsePlan(plan, artifactFile);
+ }
+
+ private ArtifactDescriptor parsePlan(PlanDescriptor plan, File artifactFile) {
+ ArtifactDescriptorBuilder builder = new ArtifactDescriptorBuilder();
+ builder.setUri(artifactFile.toURI());
+ builder.setType(BRIDGE_TYPE);
+ builder.setName(plan.getName());
+ builder.setVersion(plan.getVersion());
+
+ builder.addAttribute(new AttributeBuilder().setName(SCOPED).setValue(Boolean.toString(plan.getScoped())).build());
+ builder.addAttribute(new AttributeBuilder().setName(ATOMIC).setValue(Boolean.toString(plan.getAtomic())).build());
+
+ parseArtifacts(plan.getArtifactSpecifications(), builder);
+
+ this.hashGenerator.generateHash(builder, artifactFile);
+
+ return builder.build();
+ }
+
+ private void parseArtifacts(List<ArtifactSpecification> artifacts, ArtifactDescriptorBuilder builder) {
+ for (ArtifactSpecification artifact : artifacts) {
+ AttributeBuilder attributeBuilder = new AttributeBuilder();
+ attributeBuilder.setName(ARTIFACT);
+ attributeBuilder.setValue("");
+ attributeBuilder.putProperties(TYPE, artifact.getType());
+ attributeBuilder.putProperties(NAME, artifact.getName());
+ attributeBuilder.putProperties(VERSION, artifact.getVersionRange().toParseString());
+ builder.addAttribute(attributeBuilder.build());
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/PlanDescriptor.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/PlanDescriptor.java
new file mode 100644
index 00000000..685e0208
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/PlanDescriptor.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.plan;
+
+import java.util.List;
+
+import org.eclipse.virgo.kernel.artifact.ArtifactSpecification;
+import org.osgi.framework.Version;
+
+// TODO Javadoc
+public final class PlanDescriptor {
+
+ private final String name;
+
+ private final Version version;
+
+ private final boolean scoped;
+
+ private final boolean atomic;
+
+ private final List<ArtifactSpecification> artifactSpecifications;
+
+ public PlanDescriptor(String name, Version version, boolean scoped, boolean atomic, List<ArtifactSpecification> artifactSpecifications) {
+ this.name = name;
+ this.version = version;
+ this.scoped = scoped;
+ this.atomic = atomic;
+ this.artifactSpecifications = artifactSpecifications;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Version getVersion() {
+ return version;
+ }
+
+ public boolean getScoped() {
+ return scoped;
+ }
+
+ public boolean getAtomic() {
+ return atomic;
+ }
+
+ public List<ArtifactSpecification> getArtifactSpecifications() {
+ return artifactSpecifications;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/PlanReader.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/PlanReader.java
new file mode 100644
index 00000000..fb0b9718
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/PlanReader.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.plan;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.osgi.framework.Version;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import org.eclipse.virgo.kernel.artifact.ArtifactSpecification;
+import org.eclipse.virgo.kernel.artifact.plan.internal.PlanReaderEntityResolver;
+import org.eclipse.virgo.kernel.artifact.plan.internal.PlanReaderErrorHandler;
+import org.eclipse.virgo.util.common.PropertyPlaceholderResolver;
+import org.eclipse.virgo.util.osgi.VersionRange;
+
+/**
+ * A reader that takes a URI and transforms it into a {@link PlanDescriptor} metadata artifact
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe
+ *
+ */
+public final class PlanReader {
+
+ private static final String NAME_ATTRIBUTE = "name";
+
+ private static final String VERSION_ATTRIBUTE = "version";
+
+ private static final String SCOPED_ATTRIBUTE = "scoped";
+
+ private static final String ATOMIC_ATTRIBUTE = "atomic";
+
+ private static final String ARTIFACT_ELEMENT = "artifact";
+
+ private static final String ATTRIBUTE_ELEMENT = "attribute";
+
+ private static final String PROPERTY_ELEMENT = "property";
+
+ private static final String TYPE_ATTRIBUTE = "type";
+
+ private static final String VALUE_ATTRIBUTE = "value";
+
+ private static final String SCHEMA_LANGUAGE_ATTRIBUTE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
+
+ private static final String XSD_SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema";
+
+ private final PropertyPlaceholderResolver resolver = new PropertyPlaceholderResolver();
+
+ /**
+ * Creates a {@link PlanDescriptor} meta-data artifact from an {@link InputStream}
+ * @param inputStream from which the plan is to be read
+ * @return The plan descriptor (meta-data) from the input stream
+ */
+ public PlanDescriptor read(InputStream inputStream) {
+ try {
+ Document doc = readDocument(inputStream);
+ Element element = doc.getDocumentElement();
+ return parsePlanElement(element);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to read plan descriptor", e);
+ }
+ }
+
+ private Document readDocument(InputStream inputStream) throws ParserConfigurationException, SAXException, IOException {
+ DocumentBuilder builder = createDocumentBuilderFactory().newDocumentBuilder();
+ builder.setEntityResolver(new PlanReaderEntityResolver());
+ builder.setErrorHandler(new PlanReaderErrorHandler(LoggerFactory.getLogger(PlanBridge.class)));
+ return builder.parse(inputStream);
+ }
+
+ private DocumentBuilderFactory createDocumentBuilderFactory() {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setValidating(true);
+ factory.setNamespaceAware(true);
+ factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
+ return factory;
+ }
+
+ private PlanDescriptor parsePlanElement(Element element) {
+ String name = element.getAttribute(NAME_ATTRIBUTE);
+ Version version = new Version(element.getAttribute(VERSION_ATTRIBUTE));
+ boolean scoped = Boolean.parseBoolean(element.getAttribute(SCOPED_ATTRIBUTE));
+ boolean atomic = Boolean.parseBoolean(element.getAttribute(ATOMIC_ATTRIBUTE));
+
+ Properties attributes = parseAttributes(element);
+
+ List<ArtifactSpecification> artifactSpecifications = parseArtifactElements(element.getElementsByTagName(ARTIFACT_ELEMENT), attributes);
+
+ return new PlanDescriptor(name, version, scoped, atomic, artifactSpecifications);
+ }
+
+ private Properties parseAttributes(Element element) {
+ Properties result = new Properties();
+ NodeList attributeElements = element.getElementsByTagName(ATTRIBUTE_ELEMENT);
+ for (int x = 0; x < attributeElements.getLength(); x++) {
+ Element attribute = (Element) attributeElements.item(x);
+
+ String name = attribute.getAttribute(NAME_ATTRIBUTE);
+ String value = attribute.getAttribute(VALUE_ATTRIBUTE);
+
+ result.put(name, value);
+ }
+ return result;
+ }
+
+ private List<ArtifactSpecification> parseArtifactElements(NodeList artifactElements, Properties attributes) {
+ List<ArtifactSpecification> artifactSpecifications = new ArrayList<ArtifactSpecification>(artifactElements.getLength());
+ for (int i = 0; i < artifactElements.getLength(); i++) {
+ Element artifactElement = (Element) artifactElements.item(i);
+
+ String type = replacePlaceholders(artifactElement.getAttribute(TYPE_ATTRIBUTE), attributes);
+ String name = replacePlaceholders(artifactElement.getAttribute(NAME_ATTRIBUTE), attributes);
+ String version = replacePlaceholders(artifactElement.getAttribute(VERSION_ATTRIBUTE), attributes);
+ Map<String, String> properties = parseArtifactProperties(artifactElement, attributes);
+
+ artifactSpecifications.add(new ArtifactSpecification(type, name, new VersionRange(version), properties));
+ }
+
+ return artifactSpecifications;
+ }
+
+ private Map<String, String> parseArtifactProperties(Element artifactElement, Properties attributes) {
+ Map<String, String> result = new HashMap<String, String>();
+ NodeList propertyElements = artifactElement.getElementsByTagName(PROPERTY_ELEMENT);
+ for (int x = 0; x < propertyElements.getLength(); x++) {
+ Element propertyElement = (Element) propertyElements.item(x);
+ String name = replacePlaceholders(propertyElement.getAttribute(NAME_ATTRIBUTE), attributes);
+ String value = replacePlaceholders(propertyElement.getAttribute(VALUE_ATTRIBUTE), attributes);
+ result.put(name, value);
+ }
+ return result;
+ }
+
+ private String replacePlaceholders(String value, Properties attributes) {
+ return this.resolver.resolve(value, attributes);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/internal/PlanReaderEntityResolver.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/internal/PlanReaderEntityResolver.java
new file mode 100644
index 00000000..c7b979d3
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/internal/PlanReaderEntityResolver.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.plan.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.osgi.framework.FrameworkUtil;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public final class PlanReaderEntityResolver implements EntityResolver {
+
+ private static final String SCHEMA_LOCATION = "org/eclipse/virgo/kernel/artifact/plan/springsource-dm-server-plan.xsd";
+
+ public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
+ ClassLoader classLoader = this.getClass().getClassLoader();
+ InputStream xsdResource = classLoader.getResourceAsStream(SCHEMA_LOCATION);
+ if (xsdResource != null) {
+ InputSource source = new InputSource(xsdResource);
+ source.setPublicId(publicId);
+ source.setSystemId(systemId);
+ return source;
+ } else {
+ throw new SAXException("Plan XSD could not be loaded from bundle " + FrameworkUtil.getBundle(getClass()));
+ }
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/internal/PlanReaderErrorHandler.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/internal/PlanReaderErrorHandler.java
new file mode 100644
index 00000000..576df23b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/plan/internal/PlanReaderErrorHandler.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.plan.internal;
+
+import org.slf4j.Logger;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+public final class PlanReaderErrorHandler implements ErrorHandler {
+
+ private final Logger logger;
+
+ public PlanReaderErrorHandler(Logger logger) {
+ this.logger = logger;
+ }
+
+ public void error(SAXParseException exception) throws SAXException {
+ throw exception;
+ }
+
+ public void fatalError(SAXParseException exception) throws SAXException {
+ throw exception;
+ }
+
+ public void warning(SAXParseException exception) throws SAXException {
+ logger.warn("Ignored XML validation warning", exception);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/properties/PropertiesBridge.java b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/properties/PropertiesBridge.java
new file mode 100644
index 00000000..a1963ff6
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/java/org/eclipse/virgo/kernel/artifact/properties/PropertiesBridge.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.properties;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Properties;
+
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.repository.ArtifactBridge;
+import org.eclipse.virgo.repository.ArtifactDescriptor;
+import org.eclipse.virgo.repository.ArtifactGenerationException;
+import org.eclipse.virgo.repository.HashGenerator;
+import org.eclipse.virgo.repository.builder.ArtifactDescriptorBuilder;
+import org.eclipse.virgo.util.io.IOUtils;
+
+/**
+ * An {@link ArtifactBridge} that creates {@link ArtifactDescriptor ArtifactDescriptors} for .properties files.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe
+ *
+ */
+public final class PropertiesBridge implements ArtifactBridge {
+
+ static final String PROPERTIES_SUFFIX = ".properties";
+
+ static final String ARTIFACT_TYPE = "configuration";
+
+ private final HashGenerator hashGenerator;
+
+ public PropertiesBridge(HashGenerator hashGenerator) {
+ this.hashGenerator = hashGenerator;
+ }
+
+ public ArtifactDescriptor generateArtifactDescriptor(File artifactFile) throws ArtifactGenerationException {
+ if (artifactFile.getName().endsWith(PROPERTIES_SUFFIX)) {
+ FileReader reader = null;
+ try {
+ reader = new FileReader(artifactFile);
+ new Properties().load(reader);
+ return createArtifactDescriptor(artifactFile);
+ } catch (IOException e) {
+ throw new ArtifactGenerationException("Failed to read properties file", ARTIFACT_TYPE, e);
+ } finally {
+ IOUtils.closeQuietly(reader);
+ }
+ }
+ return null;
+ }
+
+ private ArtifactDescriptor createArtifactDescriptor(File propertiesFile) {
+ String fileName = propertiesFile.getName();
+ String name = fileName.substring(0, fileName.length() - PROPERTIES_SUFFIX.length());
+
+ ArtifactDescriptorBuilder artifactDescriptorBuilder = new ArtifactDescriptorBuilder();
+
+ artifactDescriptorBuilder //
+ .setUri(propertiesFile.toURI()) //
+ .setType(ARTIFACT_TYPE) //
+ .setName(name) //
+ .setVersion(Version.emptyVersion);
+
+ this.hashGenerator.generateHash(artifactDescriptorBuilder, propertiesFile);
+
+ return artifactDescriptorBuilder.build();
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/main/resources/org/eclipse/virgo/kernel/artifact/plan/springsource-dm-server-plan.xsd b/org.eclipse.virgo.kernel.artifact/src/main/resources/org/eclipse/virgo/kernel/artifact/plan/springsource-dm-server-plan.xsd
new file mode 100644
index 00000000..d4f0c8e5
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/main/resources/org/eclipse/virgo/kernel/artifact/plan/springsource-dm-server-plan.xsd
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:plan="http://www.springsource.org/schema/dm-server/plan"
+ targetNamespace="http://www.springsource.org/schema/dm-server/plan"
+ elementFormDefault="qualified">
+
+<!-- Types -->
+ <complexType name="nameValueType">
+ <attribute name="name" type="string" use="required" >
+ <annotation>
+ <documentation><![CDATA[The name of the attribute/property.]]></documentation>
+ </annotation>
+ </attribute>
+ <attribute name="value" type="string" use="required" >
+ <annotation>
+ <documentation><![CDATA[The value of the attribute/property.]]></documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+
+ <complexType name="attributesType">
+ <sequence minOccurs="1" maxOccurs="unbounded">
+ <element name="attribute" type="plan:nameValueType">
+ <annotation>
+ <documentation><![CDATA[An attribute for replacement in the plan.]]></documentation>
+ </annotation>
+ </element>
+ </sequence>
+ </complexType>
+
+ <complexType name="artifactType">
+ <sequence minOccurs="0" maxOccurs="unbounded">
+ <element name="property" type="plan:nameValueType">
+ <annotation>
+ <documentation>
+ <![CDATA[Defines a property for the enclosing artifact. Properties are interpreted in an artifact-specific manner.]]>
+ </documentation>
+ </annotation>
+ </element>
+ </sequence>
+ <attribute name="type" type="string" use="required" >
+ <annotation>
+ <documentation><![CDATA[The type of the artifact.]]></documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string" use="required" >
+ <annotation>
+ <documentation><![CDATA[The name of the artifact.]]></documentation>
+ </annotation>
+ </attribute>
+ <attribute name="version" type="string" use="optional" default="0">
+ <annotation>
+ <documentation><![CDATA[The version or version range for this artifact.
+This version or version number must meet the OSGi version specification. This attribute is optional and when not specified will result in a default value of "0" meaning 0 to infinity in OSGi.]]></documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+
+ <complexType name="plan">
+ <sequence minOccurs="1" maxOccurs="1">
+ <sequence minOccurs="0" maxOccurs="1">
+ <element name="attributes" type="plan:attributesType">
+ <annotation>
+ <documentation><![CDATA[The attributes for this plan]]></documentation>
+ </annotation>
+ </element>
+ </sequence>
+ <sequence minOccurs="1" maxOccurs="unbounded">
+ <element name="artifact" type="plan:artifactType">
+ <annotation>
+ <documentation><![CDATA[An artifact to include as part of this plan.]]></documentation>
+ </annotation>
+ </element>
+ </sequence>
+ </sequence>
+ <attribute name="name" type="string" use="required">
+ <annotation>
+ <documentation><![CDATA[The name of this plan. This is one component of the unique identifier for this plan along with a type of 'plan' and a specified version.]]></documentation>
+ </annotation>
+ </attribute>
+ <attribute name="version" use="required">
+ <annotation>
+ <documentation><![CDATA[The version of this plan. This version must meet the OSGi version specification. This is one component of the unique identifier for this plan along with a type of 'plan' and a specified name.]]></documentation>
+ </annotation>
+ <simpleType>
+ <restriction base="string">
+ <pattern value="\d(.\d(.\d(.([\w_-])+)?)?)?"/>
+ </restriction>
+ </simpleType>
+ </attribute>
+ <attribute name="scoped" type="boolean" use="required">
+ <annotation>
+ <documentation><![CDATA[Whether or not the artifacts in the plan should be installed into a plan-specific scope. When scoping is disabled, the artifacts are deployed into the global scope and are available for access by all other artifacts.]]></documentation>
+ </annotation>
+ </attribute>
+ <attribute name="atomic" type="boolean" use="required" >
+ <annotation>
+ <documentation><![CDATA[Whether the lifecycle of the artifacts in the plan should be tied together. Making a plan atomic means that install, start, stop and uninstall events for a single artifact in the plan will be escalated to all artifacts in the plan. Also, in an atomic plan, dm Server prevents artifacts from being in inconsistent states. For example, if one artifact should fail to start, then dm Server will stop all artifacts in the plan.]]></documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+
+<!-- Elements -->
+ <element name="plan" type="plan:plan">
+ <annotation>
+ <documentation><![CDATA[Plans are a way to group bundles together as a single logical unit in dm Server. Within a plan, bundles and services can be placed into a scope that isolates them from the rest of the system. This scoping ensures that the bundles wire to each other and see each other's services in preference to services from outside the scope. Scoping also prevents application code from leaking into the global scope or scope of another application. In addition, a plan can serve as a way to link the lifcycle of a group of bundles together atomically. This atomicity ensures that instal, start, stop, and uninstall events on a single artifact in the plan will be escalated to all artifacts in the plan.]]></documentation>
+ </annotation>
+ </element>
+
+</schema> \ No newline at end of file
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/ArtifactSpecificationTests.java b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/ArtifactSpecificationTests.java
new file mode 100644
index 00000000..1a382c9c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/ArtifactSpecificationTests.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+import org.eclipse.virgo.kernel.artifact.ArtifactSpecification;
+import org.eclipse.virgo.util.osgi.VersionRange;
+
+
+public class ArtifactSpecificationTests {
+
+ @Test
+ public void testCreateWithProperties() {
+ Map<String, String> props = new HashMap<String, String>();
+ props.put("foo", "bar");
+ ArtifactSpecification spec = new ArtifactSpecification("t", "n", new VersionRange("1.2.3"), props);
+ assertEquals("bar", spec.getProperties().get("foo"));
+ }
+
+ @Test
+ public void testCreateWithoutProperties() {
+ ArtifactSpecification spec = new ArtifactSpecification("t", "n", new VersionRange("1.2.3"));
+ assertNotNull(spec.getProperties());
+ }
+
+ @Test(expected=UnsupportedOperationException.class)
+ public void testPropertiesImmutable() {
+ ArtifactSpecification spec = new ArtifactSpecification("t", "n", new VersionRange("1.2.3"));
+ spec.getProperties().put("foo", "bar");
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/StubHashGenerator.java b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/StubHashGenerator.java
new file mode 100644
index 00000000..6572b80d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/StubHashGenerator.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact;
+
+import java.io.File;
+
+import org.eclipse.virgo.repository.HashGenerator;
+import org.eclipse.virgo.repository.builder.ArtifactDescriptorBuilder;
+
+public class StubHashGenerator implements HashGenerator {
+
+ public void generateHash(ArtifactDescriptorBuilder artifactDescriptorBuilder, File artifactFile) {
+ // Do nothing
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/bundle/BundleBridgeTests.java b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/bundle/BundleBridgeTests.java
new file mode 100644
index 00000000..8d606dba
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/bundle/BundleBridgeTests.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.bundle;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+
+import org.eclipse.virgo.kernel.artifact.StubHashGenerator;
+import org.eclipse.virgo.repository.ArtifactDescriptor;
+import org.eclipse.virgo.repository.ArtifactGenerationException;
+import org.eclipse.virgo.repository.Attribute;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+/**
+ * <p>
+ * Unit tests for {@link org.eclipse.virgo.kernel.artifact.bundle.BundleBridge BundleBridge}. Uses a combination of real bundle files and
+ * static test data.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe test case
+ *
+ */
+public class BundleBridgeTests {
+
+ //Test Data
+
+ private final static String ARTEFACT_ATTRIBUTE_NAME = "name";
+
+ private final static String ARTEFACT_ATTRIBUTE_VERSION = "version";
+ //End Test Data
+
+ private static BundleBridge BUNDLE_BRIDGE;
+
+ private static final StubBundleArtefactBridge STUB_ARTEFACT_DEFINITION = new StubBundleArtefactBridge();
+
+ private static final String BUNDLE_MANIFEST_VERSION_HEADER_NAME = "Bundle-ManifestVersion";
+
+ private static final String BUNDLE_NAME_HEADER_NAME = "Bundle-Name";
+
+ @Before
+ public void setUp() throws Exception {
+ BUNDLE_BRIDGE = new BundleBridge(new StubHashGenerator());
+ }
+
+ @Test
+ public void testFictionalURI() {
+ File file = new File("/foo/bar.jar");
+ try {
+ BUNDLE_BRIDGE.generateArtifactDescriptor(file);
+ assertTrue("Should throw exception", false);
+ } catch (ArtifactGenerationException age) {
+ assertEquals("ArtifactType in exception is incorrect", age.getArtifactType(), BundleBridge.BRIDGE_TYPE);
+ }
+ }
+
+ @Test
+ public void testBadManifest01() {
+ File file = new File("./src/test/resources/wars/testbad01.war");
+ try {
+ BUNDLE_BRIDGE.generateArtifactDescriptor(file);
+ assertTrue("Should throw exception", false);
+ } catch (ArtifactGenerationException age) {
+ assertEquals("ArtifactType in exception is incorrect", age.getArtifactType(), BundleBridge.BRIDGE_TYPE);
+ }
+ }
+
+ @Test
+ public void testBadManifest02() {
+ File file = new File("./src/test/resources/wars/testbad02.war");
+ try {
+ BUNDLE_BRIDGE.generateArtifactDescriptor(file);
+ assertTrue("Should throw exception", false);
+ } catch (ArtifactGenerationException age) {
+ assertEquals("ArtifactType in exception is incorrect", age.getArtifactType(), BundleBridge.BRIDGE_TYPE);
+ }
+ }
+
+ @Test
+ public void testGenerateArtefact() throws ArtifactGenerationException {
+ File jarsDirectory = new File("../ivy-cache/repository/org.apache.commons/com.springsource.org.apache.commons.dbcp/1.2.2.osgi/com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar");
+ File directoriesDirectory = new File("./src/test/resources/directories");
+
+ Set<ArtifactDescriptor> artefacts = new HashSet<ArtifactDescriptor>();
+
+ artefacts.add(BUNDLE_BRIDGE.generateArtifactDescriptor(jarsDirectory));
+
+ assertEquals("Wrong number of artefacts have been parsed", 1, artefacts.size());
+
+ artefacts.addAll(generateArtefacts(directoriesDirectory));
+
+ assertEquals("Wrong number of artefacts have been parsed", 2, artefacts.size());
+
+ ArtifactDescriptor stubArtefact;
+ Set<Attribute> stubAttributes;
+ Set<Attribute> testAttributes;
+
+ for (ArtifactDescriptor testArtefact : artefacts) {
+ stubArtefact = STUB_ARTEFACT_DEFINITION.generateArtifactDescriptor(new File(testArtefact.getUri()));
+
+ stubAttributes = stubArtefact.getAttribute(ARTEFACT_ATTRIBUTE_NAME);
+ testAttributes = testArtefact.getAttribute(Constants.BUNDLE_SYMBOLICNAME);
+
+ assertEquals("Error on: " + testArtefact.toString(), stubAttributes.iterator().next().getValue(),
+ testAttributes.iterator().next().getValue());
+
+ stubAttributes = stubArtefact.getAttribute(ARTEFACT_ATTRIBUTE_VERSION);
+ testAttributes = testArtefact.getAttribute(Constants.BUNDLE_VERSION);
+
+ assertEquals("Error on: " + testArtefact.toString(), stubAttributes.iterator().next().getValue(),
+ testAttributes.iterator().next().getValue());
+ }
+ }
+
+ @Test
+ public void testBuildDictionary() throws ArtifactGenerationException, IOException {
+ File testFile = new File("../ivy-cache/repository/javax.servlet/com.springsource.javax.servlet/2.5.0/com.springsource.javax.servlet-2.5.0.jar");
+
+ ArtifactDescriptor inputArtefact = BUNDLE_BRIDGE.generateArtifactDescriptor(testFile);
+
+ Dictionary<String, String> dictionary = BundleBridge.convertToDictionary(inputArtefact);
+
+ JarFile testJar = new JarFile(testFile);
+ Attributes attributes = testJar.getManifest().getMainAttributes();
+
+ testJar.close();
+
+ assertEquals("Failed to match regenerated " + Constants.BUNDLE_SYMBOLICNAME, dictionary.get(Constants.BUNDLE_SYMBOLICNAME),
+ attributes.getValue(Constants.BUNDLE_SYMBOLICNAME));
+ assertEquals("Failed to match regenerated " + Constants.BUNDLE_VERSION, dictionary.get(Constants.BUNDLE_VERSION),
+ attributes.getValue(Constants.BUNDLE_VERSION));
+ assertEquals("Failed to match regenerated " + BUNDLE_MANIFEST_VERSION_HEADER_NAME, dictionary.get(BUNDLE_MANIFEST_VERSION_HEADER_NAME),
+ attributes.getValue(BUNDLE_MANIFEST_VERSION_HEADER_NAME));
+ assertEquals("Failed to match regenerated " + BUNDLE_NAME_HEADER_NAME, dictionary.get(BUNDLE_NAME_HEADER_NAME),
+ attributes.getValue(BUNDLE_NAME_HEADER_NAME));
+
+ }
+
+ @Test
+ public void webBundleWar() throws ArtifactGenerationException {
+ ArtifactDescriptor descriptor = BUNDLE_BRIDGE.generateArtifactDescriptor(new File("src/test/resources/wars/test.war"));
+ assertNotNull(descriptor);
+ assertEquals("bundle", descriptor.getType());
+ assertEquals("com.springsource.server.admin.web", descriptor.getName());
+ assertEquals(new Version(2, 0, 0), descriptor.getVersion());
+ }
+
+ @Test
+ public void explodedBundle() throws ArtifactGenerationException {
+ ArtifactDescriptor descriptor = BUNDLE_BRIDGE.generateArtifactDescriptor(new File("src/test/resources/bundle.jar"));
+ assertNotNull(descriptor);
+ assertEquals("bundle", descriptor.getType());
+ assertEquals("exploded.bundle", descriptor.getName());
+ assertEquals(new Version(1, 0, 0), descriptor.getVersion());
+ }
+
+ private Set<ArtifactDescriptor> generateArtefacts(File directory) throws ArtifactGenerationException {
+ Set<ArtifactDescriptor> artefacts = new HashSet<ArtifactDescriptor>();
+
+ for (File fileInDir : directory.listFiles()) {
+ if(!fileInDir.getName().endsWith(".jar") && !fileInDir.getName().contains("sources")){
+ ArtifactDescriptor artefact = BUNDLE_BRIDGE.generateArtifactDescriptor(fileInDir);
+ if (artefact != null) {
+ artefacts.add(BUNDLE_BRIDGE.generateArtifactDescriptor(fileInDir));
+ }
+ }
+ }
+ return artefacts;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/bundle/StubBundleArtefactBridge.java b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/bundle/StubBundleArtefactBridge.java
new file mode 100644
index 00000000..e2ec7f64
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/bundle/StubBundleArtefactBridge.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.bundle;
+
+import java.io.File;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.virgo.repository.ArtifactBridge;
+import org.eclipse.virgo.repository.ArtifactDescriptor;
+import org.eclipse.virgo.repository.Attribute;
+import org.eclipse.virgo.repository.RepositoryAwareArtifactDescriptor;
+import org.eclipse.virgo.repository.internal.StandardAttribute;
+import org.osgi.framework.Version;
+
+/**
+ * <p>
+ * A Stub impl of Artefact Bridge, is pre-configured to return values from the test data set.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * This class is Threadsafe
+ *
+ */
+final public class StubBundleArtefactBridge implements ArtifactBridge {
+
+ private final Map<String, RepositoryAwareArtifactDescriptor> testArtefacts = new HashMap<String, RepositoryAwareArtifactDescriptor>();
+
+ public StubBundleArtefactBridge() {
+
+ testArtefacts.put(translate(TEST_FILE_URI), TEST_ARTEFACT);
+ testArtefacts.put(translate(TEST_DIRECTORY_URI), TEST_DIRECTORY_ARTEFACT);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ArtifactDescriptor generateArtifactDescriptor(File artifact) {
+ return this.testArtefacts.get(artifact.getName());
+ }
+
+ private String translate(URI uri) {
+ return new File(uri).getName();
+ }
+
+ //TEST DATA
+
+ private static final URI TEST_DIRECTORY_URI = URI.create("file:/src/test/resources/directories/y.different-" + new Version("1.2.3"));
+
+ private static final Set<Attribute> TEST_ATTRIBUTE_SET_DIRECTORY = createAttributeSet("y.different", new Version("1.2.3"), TEST_DIRECTORY_URI);
+
+ private final static RepositoryAwareArtifactDescriptor TEST_DIRECTORY_ARTEFACT = new StubRepositoryAwareArtifactDescriptor(TEST_DIRECTORY_URI, "y.different", new Version("1.2.3"), TEST_ATTRIBUTE_SET_DIRECTORY);
+
+ private final static URI TEST_FILE_URI = URI.create("file:/../ivy-cache/repository/org.apache.commons/com.springsource.org.apache.commons.dbcp/1.2.2.osgi/" + "com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar");
+
+ private static final Set<Attribute> TEST_ATTRIBUTE_SET = createAttributeSet("com.springsource.org.apache.commons.dbcp", new Version("1.2.2.osgi"), TEST_FILE_URI);
+
+ private final static RepositoryAwareArtifactDescriptor TEST_ARTEFACT = new StubRepositoryAwareArtifactDescriptor(TEST_FILE_URI, "com.springsource.org.apache.commons.dbcp", new Version("1.2.2.osgi"), TEST_ATTRIBUTE_SET);
+
+ private static Set<Attribute> createAttributeSet(String name, Version version, URI uri) {
+ Set<Attribute> attributes = new HashSet<Attribute>();
+ attributes.add(new StandardAttribute("type", "test"));
+ attributes.add(new StandardAttribute("name", name));
+ attributes.add(new StandardAttribute("version", version.toString()));
+ attributes.add(new StandardAttribute("uri", uri.toString()));
+ return attributes;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/bundle/StubRepositoryAwareArtifactDescriptor.java b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/bundle/StubRepositoryAwareArtifactDescriptor.java
new file mode 100644
index 00000000..4428981d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/bundle/StubRepositoryAwareArtifactDescriptor.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.bundle;
+
+import java.io.File;
+import java.net.URI;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.repository.Attribute;
+import org.eclipse.virgo.repository.RepositoryAwareArtifactDescriptor;
+
+class StubRepositoryAwareArtifactDescriptor implements RepositoryAwareArtifactDescriptor {
+
+ private final URI uri;
+
+ private final String name;
+
+ private final Version version;
+
+ private final Set<Attribute> attributes;
+
+ public StubRepositoryAwareArtifactDescriptor(URI uri, String name, Version version, Set<Attribute> attributes) {
+ this.uri = uri;
+ this.name = name;
+ this.version = version;
+ this.attributes = attributes;
+ }
+
+ public Set<Attribute> getAttribute(String name) {
+ Set<Attribute> matchingAttribs = new HashSet<Attribute>();
+ for(Attribute attrib : this.attributes){
+ if(attrib.getKey().equals(name)){
+ matchingAttribs.add(attrib);
+ }
+ }
+ return matchingAttribs;
+ }
+
+ public Set<Attribute> getAttributes() {
+ return this.attributes;
+ }
+
+ public String getFilename() {
+ return new File(this.uri).getName();
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getType() {
+ return "test_type";
+ }
+
+ public URI getUri() {
+ return this.uri;
+ }
+
+ public Version getVersion() {
+ return this.version;
+ }
+
+ public String getRepositoryName() {
+ return "test-repo";
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/fs/internal/DirectoryArtifactFSTests.java b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/fs/internal/DirectoryArtifactFSTests.java
new file mode 100644
index 00000000..fd240e05
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/fs/internal/DirectoryArtifactFSTests.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.fs.internal;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.eclipse.virgo.kernel.artifact.fs.internal.DirectoryArtifactFS;
+import org.eclipse.virgo.kernel.artifact.fs.internal.FileArtifactFSEntry;
+import org.junit.Test;
+
+
+public class DirectoryArtifactFSTests {
+
+ private final DirectoryArtifactFS artifactFS = new DirectoryArtifactFS(new File("target"));
+
+ @Test
+ public void getEntry() {
+ assertTrue(this.artifactFS.getEntry("test") instanceof FileArtifactFSEntry);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFSEntryTests.java b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFSEntryTests.java
new file mode 100644
index 00000000..5d616113
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFSEntryTests.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.fs.internal;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.util.jar.JarFile;
+
+import org.eclipse.virgo.kernel.artifact.fs.internal.FileArtifactFSEntry;
+import org.junit.Test;
+
+public class FileArtifactFSEntryTests {
+
+ private final File file;
+
+ public FileArtifactFSEntryTests() throws Exception {
+ this.file = new File("src/test/resources/artifacts/exploded");
+ new FileArtifactFSEntry(this.file, new File(this.file, JarFile.MANIFEST_NAME));
+ new FileArtifactFSEntry(this.file, new File(this.file, "META-INF/"));
+ }
+
+ @Test
+ public void getNameRoot() {
+ assertEquals("", new FileArtifactFSEntry(this.file, this.file).getPath());
+ }
+
+ @Test
+ public void getName() {
+ assertEquals("test", new FileArtifactFSEntry(this.file, new File(this.file, "test")).getPath());
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFSTests.java b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFSTests.java
new file mode 100644
index 00000000..ee40067e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/fs/internal/FileArtifactFSTests.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.fs.internal;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.eclipse.virgo.kernel.artifact.fs.internal.FileArtifactFS;
+import org.eclipse.virgo.kernel.artifact.fs.internal.FileArtifactFSEntry;
+import org.junit.Test;
+
+
+public class FileArtifactFSTests {
+
+ private final FileArtifactFS artifactFS = new FileArtifactFS(new File(".classpath"));
+
+ @Test(expected = IllegalArgumentException.class)
+ public void constructorDirectory() {
+ new FileArtifactFS(new File("target"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void getEntryNonNull() {
+ this.artifactFS.getEntry("test");
+ }
+
+ @Test
+ public void getEntry() {
+ assertTrue(this.artifactFS.getEntry(null) instanceof FileArtifactFSEntry);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/library/LibraryBridgeTests.java b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/library/LibraryBridgeTests.java
new file mode 100644
index 00000000..fdc2bcc3
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/library/LibraryBridgeTests.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.library;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+
+import org.junit.Test;
+
+
+import org.eclipse.virgo.kernel.artifact.StubHashGenerator;
+import org.eclipse.virgo.kernel.artifact.library.LibraryBridge;
+import org.eclipse.virgo.repository.ArtifactDescriptor;
+import org.eclipse.virgo.repository.ArtifactGenerationException;
+
+/**
+ */
+public class LibraryBridgeTests {
+
+ @Test
+ public void testValidLibraryFile() throws ArtifactGenerationException {
+ LibraryBridge bridge = new LibraryBridge(new StubHashGenerator());
+
+ ArtifactDescriptor descriptor = bridge.generateArtifactDescriptor(new File("src/test/resources/libraries/test.libd"));
+ assertNotNull(descriptor);
+
+ assertEquals("test.library", descriptor.getName());
+ assertEquals("1.2.0", descriptor.getAttribute("Library-Version").iterator().next().getValue());
+ assertEquals(3, descriptor.getAttribute("Import-Bundle").size());
+ }
+
+ @Test
+ public void testNotALibraryFile() throws ArtifactGenerationException {
+ LibraryBridge bridge = new LibraryBridge(new StubHashGenerator());
+
+ ArtifactDescriptor descriptor = bridge.generateArtifactDescriptor(new File("src/test/resources/libraries/test.foo"));
+ assertNull(descriptor);
+ }
+
+ @Test(expected = ArtifactGenerationException.class)
+ public void testInvalidLibraryFile() throws ArtifactGenerationException {
+ LibraryBridge bridge = new LibraryBridge(new StubHashGenerator());
+ bridge.generateArtifactDescriptor(new File("src/test/resources/libraries/invalid.libd"));
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/par/ParBridgeTests.java b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/par/ParBridgeTests.java
new file mode 100644
index 00000000..459889f3
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/par/ParBridgeTests.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.par;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+
+import org.junit.Test;
+import org.osgi.framework.Version;
+
+
+import org.eclipse.virgo.kernel.artifact.StubHashGenerator;
+import org.eclipse.virgo.kernel.artifact.par.ParBridge;
+import org.eclipse.virgo.repository.ArtifactDescriptor;
+import org.eclipse.virgo.repository.ArtifactGenerationException;
+
+
+/**
+ *
+ */
+public class ParBridgeTests {
+
+ private final ParBridge parBridge = new ParBridge(new StubHashGenerator());
+
+ @Test
+ public void descriptorGeneration() throws ArtifactGenerationException {
+ ArtifactDescriptor descriptor = this.parBridge.generateArtifactDescriptor(new File("src/test/resources/pars/basic.par"));
+ assertDescriptor(descriptor, "par", "basic", new Version(1,2,3), "Basic Par", "A basic PAR file for the unit tests");
+ }
+
+ @Test
+ public void generationWithNoManifest() throws ArtifactGenerationException {
+ ArtifactDescriptor descriptor = this.parBridge.generateArtifactDescriptor(new File("src/test/resources/pars/no-manifest.par"));
+ assertNull(descriptor);
+ }
+
+ @Test
+ public void generationWithNoApplicationSymbolicName() throws ArtifactGenerationException {
+ ArtifactDescriptor descriptor = this.parBridge.generateArtifactDescriptor(new File("src/test/resources/pars/no-asn.par"));
+ assertNull(descriptor);
+ }
+
+ @Test
+ public void generationWithNoApplicationVersion() throws ArtifactGenerationException {
+ ArtifactDescriptor descriptor = this.parBridge.generateArtifactDescriptor(new File("src/test/resources/pars/no-version.par"));
+ assertDescriptor(descriptor, "par", "basic", Version.emptyVersion, "Basic Par", "A basic PAR file for the unit tests");
+ }
+
+ @Test
+ public void generationWithNoName() throws ArtifactGenerationException {
+ ArtifactDescriptor descriptor = this.parBridge.generateArtifactDescriptor(new File("src/test/resources/pars/no-name.par"));
+ assertDescriptor(descriptor, "par", "basic", new Version(1,2,3), null, "A basic PAR file for the unit tests");
+ }
+
+ @Test
+ public void generationWithNoDescription() throws ArtifactGenerationException {
+ ArtifactDescriptor descriptor = this.parBridge.generateArtifactDescriptor(new File("src/test/resources/pars/no-description.par"));
+ assertDescriptor(descriptor, "par", "basic", new Version(1,2,3), "Basic Par", null);
+ }
+
+ @Test
+ public void generationWithIllegalApplicationSymbolicName() throws Exception {
+ try {
+ this.parBridge.generateArtifactDescriptor(new File("src/test/resources/pars/illegal-asn.par"));
+ fail("Illegal Application-SymbolicName did not throw an ArtifactGenerationException");
+ } catch (ArtifactGenerationException age) {
+ assertEquals("Application-SymbolicName '.@$%' contains illegal characters", age.getMessage());
+ }
+ }
+
+ @Test
+ public void generationWithIllegalApplicationVersion() throws Exception {
+ try {
+ this.parBridge.generateArtifactDescriptor(new File("src/test/resources/pars/illegal-version.par"));
+ fail("Illegal Application-Version did not throw an ArtifactGenerationException");
+ } catch (ArtifactGenerationException age) {
+ assertEquals("Version 'alpha' is ill-formed", age.getMessage());
+ }
+ }
+
+ @Test(expected=ArtifactGenerationException.class)
+ public void generationWithMissingPar() throws ArtifactGenerationException {
+ this.parBridge.generateArtifactDescriptor(new File("src/test/resources/pars/not-there.par"));
+ }
+
+ private void assertDescriptor(ArtifactDescriptor descriptor, String type, String symbolicName, Version version, String name, String description) {
+ assertNotNull(descriptor);
+ assertEquals(type, descriptor.getType());
+ assertEquals(symbolicName, descriptor.getName());
+ assertEquals(version, descriptor.getVersion());
+ if (name != null) {
+ assertEquals(name, descriptor.getAttribute("Application-Name").iterator().next().getValue());
+ } else {
+ assertTrue(descriptor.getAttribute("Application-Name").isEmpty());
+ }
+
+ if (description != null) {
+ assertEquals(description, descriptor.getAttribute("Application-Description").iterator().next().getValue());
+ } else {
+ assertTrue(descriptor.getAttribute("Application-Description").isEmpty());
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/plan/PlanBridgeTests.java b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/plan/PlanBridgeTests.java
new file mode 100644
index 00000000..97a5704b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/plan/PlanBridgeTests.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.plan;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Test;
+import org.osgi.framework.Version;
+
+
+import org.eclipse.virgo.kernel.artifact.StubHashGenerator;
+import org.eclipse.virgo.kernel.artifact.plan.PlanBridge;
+import org.eclipse.virgo.repository.ArtifactDescriptor;
+import org.eclipse.virgo.repository.ArtifactGenerationException;
+import org.eclipse.virgo.repository.Attribute;
+
+public class PlanBridgeTests {
+
+ private final PlanBridge bridge = new PlanBridge(new StubHashGenerator());
+
+ @Test(expected = ArtifactGenerationException.class)
+ public void testBadPlanFile() throws ArtifactGenerationException {
+ bridge.generateArtifactDescriptor(new File("src/test/resources/plans/malformed.plan"));
+ }
+
+ @Test()
+ public void testNotAPlanFile() throws ArtifactGenerationException {
+ assertNull(bridge.generateArtifactDescriptor(new File("src/test/resources/plans/not-a-plan.xml")));
+ }
+
+ @Test
+ public void testSingleArtifactPlan() throws ArtifactGenerationException {
+ org.eclipse.virgo.repository.ArtifactDescriptor artefact = bridge.generateArtifactDescriptor(new File(
+ "src/test/resources/plans/single-artifact.plan"));
+ assertEquals("plan", artefact.getType());
+ assertEquals("single-artifact.plan", artefact.getName());
+ assertEquals(new Version(1, 0, 0), artefact.getVersion());
+
+ Set<Attribute> attributes = artefact.getAttribute("artifact");
+ assertEquals(1, attributes.size());
+ Map<String, Set<String>> properties = attributes.iterator().next().getProperties();
+ assertEquals("bundle", getProperty("type", properties));
+ assertEquals("org.springframework.context.support", getProperty("name", properties));
+ assertEquals("[1.0.0, 2.0.0)", getProperty("version", properties));
+ }
+
+ @Test
+ public void testMultiArtifactPlan() throws ArtifactGenerationException {
+ ArtifactDescriptor artefact = bridge.generateArtifactDescriptor(new File("src/test/resources/plans/multi-artifact.plan"));
+ assertEquals("plan", artefact.getType());
+ assertEquals("multi-artifact.plan", artefact.getName());
+ assertEquals(new Version(1, 0, 0), artefact.getVersion());
+
+ Set<Attribute> attributes = artefact.getAttribute("artifact");
+ assertEquals(3, attributes.size());
+ for (Attribute attribute : attributes) {
+ Map<String, Set<String>> properties = attribute.getProperties();
+ String type = getProperty("type", properties);
+ if ("alpha".equals(type)) {
+ assertEquals("org.springframework.core", getProperty("name", properties));
+ assertEquals("0.0.0", getProperty("version", properties));
+ } else if ("bravo".equals(type)) {
+ assertEquals("org.springframework.context", getProperty("name", properties));
+ assertEquals("1.0.0", getProperty("version", properties));
+ } else if ("charlie".equals(type)) {
+ assertEquals("org.springframework.context.support", getProperty("name", properties));
+ assertEquals("[1.0.0, 2.0.0)", getProperty("version", properties));
+ }
+ }
+ }
+
+ private String getProperty(String key, Map<String, Set<String>> properties) {
+ return properties.get(key).iterator().next();
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/plan/PlanReaderTests.java b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/plan/PlanReaderTests.java
new file mode 100644
index 00000000..a2a9e4fd
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/plan/PlanReaderTests.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.plan;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.List;
+
+import org.junit.Test;
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.artifact.ArtifactSpecification;
+import org.eclipse.virgo.kernel.artifact.plan.PlanDescriptor;
+import org.eclipse.virgo.kernel.artifact.plan.PlanReader;
+import org.eclipse.virgo.util.osgi.VersionRange;
+
+public class PlanReaderTests {
+
+ private final PlanReader reader = new PlanReader();
+
+ @Test(expected = RuntimeException.class)
+ public void testBadPlanFile() throws FileNotFoundException {
+ reader.read(new FileInputStream("src/test/resources/plans/malformed.plan"));
+ }
+
+ @Test
+ public void testSingleArtifactPlan() throws FileNotFoundException {
+ PlanDescriptor plan = reader.read(new FileInputStream("src/test/resources/plans/single-artifact.plan"));
+ assertEquals("single-artifact.plan", plan.getName());
+ assertEquals(new Version(1, 0, 0), plan.getVersion());
+
+ List<ArtifactSpecification> artifactSpecifications = plan.getArtifactSpecifications();
+ assertEquals(1, artifactSpecifications.size());
+ ArtifactSpecification artifactSpecification = artifactSpecifications.iterator().next();
+ assertEquals("bundle", artifactSpecification.getType());
+ assertEquals("org.springframework.context.support", artifactSpecification.getName());
+ assertEquals(new VersionRange("[1.0.0, 2.0.0)"), artifactSpecification.getVersionRange());
+ assertNotNull(artifactSpecification.getProperties());
+ assertTrue(artifactSpecification.getProperties().isEmpty());
+ }
+
+ @Test
+ public void testSingleArtifactPlanWithAttributes() throws FileNotFoundException {
+ PlanDescriptor plan = reader.read(new FileInputStream("src/test/resources/plans/attributes.plan"));
+ assertEquals("single-artifact.plan", plan.getName());
+ assertEquals(new Version(1, 0, 0), plan.getVersion());
+
+ List<ArtifactSpecification> artifactSpecifications = plan.getArtifactSpecifications();
+ assertEquals(1, artifactSpecifications.size());
+ ArtifactSpecification artifactSpecification = artifactSpecifications.iterator().next();
+ assertEquals("bundle", artifactSpecification.getType());
+ assertEquals("org.springframework.context.support", artifactSpecification.getName());
+ assertEquals(new VersionRange("[1.0.0, 2.0.0)"), artifactSpecification.getVersionRange());
+ }
+
+ @Test
+ public void testSingleArtifactPlanWithProperties() throws FileNotFoundException {
+ PlanDescriptor plan = reader.read(new FileInputStream("src/test/resources/plans/properties.plan"));
+ assertEquals("properties.plan", plan.getName());
+ assertEquals(new Version(1, 0, 0), plan.getVersion());
+
+ List<ArtifactSpecification> artifactSpecifications = plan.getArtifactSpecifications();
+ assertEquals(1, artifactSpecifications.size());
+ ArtifactSpecification artifactSpecification = artifactSpecifications.iterator().next();
+ assertEquals("bundle", artifactSpecification.getType());
+ assertEquals("my.webapp", artifactSpecification.getName());
+ assertEquals(new VersionRange("[1.0.0, 2.0.0)"), artifactSpecification.getVersionRange());
+ assertEquals("/foo", artifactSpecification.getProperties().get("Web-ContextPath"));
+ }
+
+ @Test
+ public void testMultiArtifactPlan() throws FileNotFoundException {
+ PlanDescriptor plan = reader.read(new FileInputStream("src/test/resources/plans/multi-artifact.plan"));
+ assertEquals("multi-artifact.plan", plan.getName());
+ assertEquals(new Version(1, 0, 0), plan.getVersion());
+
+ List<ArtifactSpecification> artifactSpecifications = plan.getArtifactSpecifications();
+ assertEquals(3, artifactSpecifications.size());
+ for (ArtifactSpecification artifactSpecification : artifactSpecifications) {
+ String type = artifactSpecification.getType();
+ if ("alpha".equals(type)) {
+ assertEquals("org.springframework.core", artifactSpecification.getName());
+ assertEquals(new VersionRange("0"), artifactSpecification.getVersionRange());
+ } else if ("bravo".equals(type)) {
+ assertEquals("org.springframework.context", artifactSpecification.getName());
+ assertEquals(new VersionRange("1.0.0"), artifactSpecification.getVersionRange());
+ } else if ("charlie".equals(type)) {
+ assertEquals("org.springframework.context.support", artifactSpecification.getName());
+ assertEquals(new VersionRange("[1.0.0, 2.0.0)"), artifactSpecification.getVersionRange());
+ }
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/properties/PropertiesBridgeTests.java b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/properties/PropertiesBridgeTests.java
new file mode 100644
index 00000000..4f046b2b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/java/org/eclipse/virgo/kernel/artifact/properties/PropertiesBridgeTests.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.artifact.properties;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+
+import org.junit.Test;
+
+
+import org.eclipse.virgo.kernel.artifact.StubHashGenerator;
+import org.eclipse.virgo.kernel.artifact.properties.PropertiesBridge;
+import org.eclipse.virgo.repository.ArtifactDescriptor;
+import org.eclipse.virgo.repository.ArtifactGenerationException;
+
+/**
+ */
+public class PropertiesBridgeTests {
+
+ @Test
+ public void testGeneratePropertiesFile() throws ArtifactGenerationException {
+ PropertiesBridge bridge = new PropertiesBridge(new StubHashGenerator());
+ ArtifactDescriptor result = bridge.generateArtifactDescriptor(new File("src/test/resources/properties/foo.properties"));
+ assertNotNull(result);
+ }
+
+ @Test(expected = ArtifactGenerationException.class)
+ public void testFileDoesNotExist() throws ArtifactGenerationException {
+ PropertiesBridge bridge = new PropertiesBridge(new StubHashGenerator());
+
+ File file = new File("src/test/resources/properties/not.exist.properties");
+ bridge.generateArtifactDescriptor(file);
+ }
+
+ @Test
+ public void testGenerateNotPropertiesFile() throws ArtifactGenerationException {
+ PropertiesBridge bridge = new PropertiesBridge(new StubHashGenerator());
+ ArtifactDescriptor descriptor = bridge.generateArtifactDescriptor(new File("src/test/resources/bar.noterties"));
+ assertNull(descriptor);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/artefacts/exploded/META-INF/MANIFEST.MF b/org.eclipse.virgo.kernel.artifact/src/test/resources/artefacts/exploded/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/artefacts/exploded/META-INF/MANIFEST.MF
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/artefacts/exploded/META-INF/web/index.jsp b/org.eclipse.virgo.kernel.artifact/src/test/resources/artefacts/exploded/META-INF/web/index.jsp
new file mode 100644
index 00000000..8102008f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/artefacts/exploded/META-INF/web/index.jsp
@@ -0,0 +1,12 @@
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+ pageEncoding="ISO-8859-1"%>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>Hello Web!</title>
+</head>
+<body>
+<p>Hello Web!</p>
+</body>
+</html> \ No newline at end of file
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/artefacts/exploded/somefile.txt b/org.eclipse.virgo.kernel.artifact/src/test/resources/artefacts/exploded/somefile.txt
new file mode 100644
index 00000000..c57eff55
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/artefacts/exploded/somefile.txt
@@ -0,0 +1 @@
+Hello World! \ No newline at end of file
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/artifacts/simple.jar b/org.eclipse.virgo.kernel.artifact/src/test/resources/artifacts/simple.jar
new file mode 100644
index 00000000..7efafc13
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/artifacts/simple.jar
Binary files differ
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/bundle.jar/META-INF/MANIFEST.MF b/org.eclipse.virgo.kernel.artifact/src/test/resources/bundle.jar/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..4a7652cc
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/bundle.jar/META-INF/MANIFEST.MF
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: exploded.bundle
+Bundle-Version: 1.0
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/directories/y.different-1.2.3/META-INF/MANIFEST.MF b/org.eclipse.virgo.kernel.artifact/src/test/resources/directories/y.different-1.2.3/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..582885d7
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/directories/y.different-1.2.3/META-INF/MANIFEST.MF
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: y.different
+Export-Package: x
+Bundle-Version: 1.2.3
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/libraries/invalid.libd b/org.eclipse.virgo.kernel.artifact/src/test/resources/libraries/invalid.libd
new file mode 100644
index 00000000..ff55009f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/libraries/invalid.libd
@@ -0,0 +1,3 @@
+Manifest-Version: 1
+Library-Version: 1.2
+Import-Bundle: a,b,c \ No newline at end of file
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/libraries/test.libd b/org.eclipse.virgo.kernel.artifact/src/test/resources/libraries/test.libd
new file mode 100644
index 00000000..3e4e6f06
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/libraries/test.libd
@@ -0,0 +1,4 @@
+Manifest-Version: 1
+Library-SymbolicName: test.library
+Library-Version: 1.2
+Import-Bundle: a,b,c \ No newline at end of file
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/basic.par/META-INF/MANIFEST.MF b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/basic.par/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..8099c758
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/basic.par/META-INF/MANIFEST.MF
@@ -0,0 +1,4 @@
+Application-SymbolicName: basic
+Application-Version: 1.2.3
+Application-Name: Basic Par
+Application-Description: A basic PAR file for the unit tests
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/illegal-asn.par/META-INF/MANIFEST.MF b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/illegal-asn.par/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..e5fa4593
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/illegal-asn.par/META-INF/MANIFEST.MF
@@ -0,0 +1,4 @@
+Application-SymbolicName: .@$%
+Application-Version: 1.2.3
+Application-Name: Basic Par
+Application-Description: A basic PAR file for the unit tests
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/illegal-version.par/META-INF/MANIFEST.MF b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/illegal-version.par/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..6488d37c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/illegal-version.par/META-INF/MANIFEST.MF
@@ -0,0 +1,4 @@
+Application-SymbolicName: basic
+Application-Version: alpha
+Application-Name: Basic Par
+Application-Description: A basic PAR file for the unit tests
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-asn.par/META-INF/MANIFEST.MF b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-asn.par/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..f9f79e57
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-asn.par/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Application-Version: 1.2.3
+Application-Name: Basic Par
+Application-Description: A basic PAR file for the unit tests
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-description.par/META-INF/MANIFEST.MF b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-description.par/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..fd589a8f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-description.par/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Application-SymbolicName: basic
+Application-Version: 1.2.3
+Application-Name: Basic Par
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-manifest.par/META-INF/dummy.txt b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-manifest.par/META-INF/dummy.txt
new file mode 100644
index 00000000..0fa94231
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-manifest.par/META-INF/dummy.txt
@@ -0,0 +1 @@
+Just a file to keep the directory around \ No newline at end of file
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-name.par/META-INF/MANIFEST.MF b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-name.par/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..ad855b69
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-name.par/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Application-SymbolicName: basic
+Application-Version: 1.2.3
+Application-Description: A basic PAR file for the unit tests
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-version.par/META-INF/MANIFEST.MF b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-version.par/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..a5a84ba6
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/pars/no-version.par/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Application-SymbolicName: basic
+Application-Name: Basic Par
+Application-Description: A basic PAR file for the unit tests
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/attributes.plan b/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/attributes.plan
new file mode 100644
index 00000000..5ae8d8c7
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/attributes.plan
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plan name="single-artifact.plan" version="1.0.0" scoped="true" atomic="true"
+ xmlns="http://www.springsource.org/schema/dm-server/plan"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springsource.org/schema/dm-server/plan
+ http://www.springsource.org/schema/dm-server/plan/springsource-dm-server-plan.xsd">
+
+ <attributes>
+ <attribute name="version" value="[1.0.0, 2.0.0)"/>
+
+ </attributes>
+ <artifact type="bundle" name="org.springframework.context.support" version="${version}"/>
+
+</plan> \ No newline at end of file
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/malformed.plan b/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/malformed.plan
new file mode 100644
index 00000000..71cc5c15
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/malformed.plan
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plan name="malformed.plan" version="1.0.0"
+ xmlns="http://www.springsource.org/schema/dm-server/plan"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springsource.org/schema/dm-server/plan
+ http://www.springsource.org/schema/dm-server/plan/springsource-dm-server-plan.xsd">
+ <artifact type="bundle"/>
+</plan> \ No newline at end of file
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/multi-artifact.plan b/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/multi-artifact.plan
new file mode 100644
index 00000000..ea5363d0
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/multi-artifact.plan
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plan name="multi-artifact.plan" version="1.0.0" scoped="true" atomic="true"
+ xmlns="http://www.springsource.org/schema/dm-server/plan"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springsource.org/schema/dm-server/plan
+ http://www.springsource.org/schema/dm-server/plan/springsource-dm-server-plan.xsd">
+
+ <artifact type="alpha" name="org.springframework.core"/>
+ <artifact type="bravo" name="org.springframework.context" version="1.0.0"/>
+ <artifact type="charlie" name="org.springframework.context.support" version="[1.0.0, 2.0.0)"/>
+
+</plan> \ No newline at end of file
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/properties.plan b/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/properties.plan
new file mode 100644
index 00000000..8e76e718
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/properties.plan
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plan name="properties.plan" version="1.0.0" scoped="true" atomic="true"
+ xmlns="http://www.springsource.org/schema/dm-server/plan"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springsource.org/schema/dm-server/plan
+ http://www.springsource.org/schema/dm-server/plan/springsource-dm-server-plan.xsd">
+
+ <artifact type="bundle" name="my.webapp" version="[1.0.0, 2.0.0)">
+ <property name="Web-ContextPath" value="/foo"/>
+ </artifact>
+
+</plan> \ No newline at end of file
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/single-artifact.plan b/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/single-artifact.plan
new file mode 100644
index 00000000..e5377970
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/plans/single-artifact.plan
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plan name="single-artifact.plan" version="1.0.0" scoped="true" atomic="true"
+ xmlns="http://www.springsource.org/schema/dm-server/plan"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springsource.org/schema/dm-server/plan
+ http://www.springsource.org/schema/dm-server/plan/springsource-dm-server-plan.xsd">
+
+ <artifact type="bundle" name="org.springframework.context.support" version="[1.0.0, 2.0.0)"/>
+
+</plan> \ No newline at end of file
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/properties/foo.properties b/org.eclipse.virgo.kernel.artifact/src/test/resources/properties/foo.properties
new file mode 100644
index 00000000..74d0a43f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/properties/foo.properties
@@ -0,0 +1 @@
+foo=bar
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/wars/test.war b/org.eclipse.virgo.kernel.artifact/src/test/resources/wars/test.war
new file mode 100644
index 00000000..c08c7316
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/wars/test.war
Binary files differ
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/wars/testbad01.war b/org.eclipse.virgo.kernel.artifact/src/test/resources/wars/testbad01.war
new file mode 100644
index 00000000..677a6ba6
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/wars/testbad01.war
Binary files differ
diff --git a/org.eclipse.virgo.kernel.artifact/src/test/resources/wars/testbad02.war b/org.eclipse.virgo.kernel.artifact/src/test/resources/wars/testbad02.war
new file mode 100644
index 00000000..4b90d403
--- /dev/null
+++ b/org.eclipse.virgo.kernel.artifact/src/test/resources/wars/testbad02.war
@@ -0,0 +1 @@
+This is not a war file really \ No newline at end of file

Back to the top