Sort Members
diff --git a/src/main/java/org/purl/wf4ever/robundle/Bundle.java b/src/main/java/org/purl/wf4ever/robundle/Bundle.java
index 9b23cfe..dd34433 100644
--- a/src/main/java/org/purl/wf4ever/robundle/Bundle.java
+++ b/src/main/java/org/purl/wf4ever/robundle/Bundle.java
@@ -59,6 +59,17 @@
 		return getRoot().getFileSystem();
 	}
 
+	public Manifest getManifest() throws IOException {
+		if (manifest == null) {
+			synchronized (this) {
+				if (manifest == null) {
+					manifest = readOrPopulateManifest();
+				}
+			}
+		}
+		return manifest;
+	}
+
 	public Path getPath(String path) {
 		return getRoot().resolve(path);
 	}
@@ -76,21 +87,6 @@
 		return deleteOnClose;
 	}
 
-	public void setDeleteOnClose(boolean deleteOnClose) {
-		this.deleteOnClose = deleteOnClose;
-	}
-
-	public Manifest getManifest() throws IOException {
-		if (manifest == null) {
-			synchronized (this) {
-				if (manifest == null) {
-					manifest = readOrPopulateManifest();
-				}
-			}
-		}
-		return manifest;
-	}
-
 	protected Manifest readOrPopulateManifest() throws IOException {
 		Manifest newManifest = new Manifest(this);
 		Path manifestPath = Bundles.getManifestPath(this);
@@ -113,4 +109,8 @@
 		return newManifest;
 	}
 
+	public void setDeleteOnClose(boolean deleteOnClose) {
+		this.deleteOnClose = deleteOnClose;
+	}
+
 }
diff --git a/src/main/java/org/purl/wf4ever/robundle/Bundles.java b/src/main/java/org/purl/wf4ever/robundle/Bundles.java
index 52cc055..4068ee3 100644
--- a/src/main/java/org/purl/wf4ever/robundle/Bundles.java
+++ b/src/main/java/org/purl/wf4ever/robundle/Bundles.java
@@ -102,6 +102,26 @@
 		return fileName.substring(0, lastDot);
 	}
 
+	public static Path getAnnotations(Bundle bundle) throws IOException {
+		Path dir = bundle.getFileSystem().getPath(DOT_RO, ANNOTATIONS);
+		Files.createDirectories(dir);
+		return dir;
+	}
+
+	public static Path getManifestPath(Bundle bundle) {
+		return bundle.getRoot().resolve(DOT_RO).resolve(MANIFEST_JSON);
+	}
+
+	public static String getMimeType(Bundle bundle) throws IOException {
+		Path mimetypePath = bundle.getRoot().resolve(
+				BundleFileSystemProvider.MIMETYPE_FILE);
+		String mimetype = getStringValue(mimetypePath);
+		if (mimetype == null || mimetype.isEmpty()) {
+			return BundleFileSystemProvider.APPLICATION_VND_WF4EVER_ROBUNDLE_ZIP;
+		}
+		return mimetype.trim();
+	}
+
 	public static URI getReference(Path path) throws IOException {
 		if (path == null || isMissing(path)) {
 			return null;
@@ -151,20 +171,6 @@
 		return !isReference(path) && Files.isRegularFile(path);
 	}
 
-	public static Bundle openBundle(URL url) throws IOException {
-		if ("file.".equals(url.getProtocol())) {
-			try {
-				return openBundle(Paths.get(url.toURI()));
-			} catch (URISyntaxException e) {
-				throw new IllegalArgumentException("Invalid URL " + url, e);
-			}
-		} else {
-			try (InputStream in = url.openStream()) {
-				return openBundle(in);
-			}
-		}
-	}
-
 	public static Bundle openBundle(InputStream in) throws IOException {
 		Path path = TemporaryFiles.temporaryBundle();
 		Files.copy(in, path);
@@ -179,6 +185,20 @@
 		return new Bundle(fs.getRootDirectory(), false);
 	}
 
+	public static Bundle openBundle(URL url) throws IOException {
+		if ("file.".equals(url.getProtocol())) {
+			try {
+				return openBundle(Paths.get(url.toURI()));
+			} catch (URISyntaxException e) {
+				throw new IllegalArgumentException("Invalid URL " + url, e);
+			}
+		} else {
+			try (InputStream in = url.openStream()) {
+				return openBundle(in);
+			}
+		}
+	}
+
 	public static Bundle openBundleReadOnly(Path zip) throws IOException {
 		Path tmpBundle = TemporaryFiles.temporaryBundle();
 		// BundleFileSystemProvider requires write-access, so we'll have to copy
@@ -271,6 +291,33 @@
 		}
 	}
 
+	public static void setMimeType(Bundle bundle, String mimetype)
+			throws IOException {
+		if (!ASCII.newEncoder().canEncode(mimetype)) {
+			throw new IllegalArgumentException("mimetype must be ASCII, not "
+					+ mimetype);
+		}
+		if (mimetype.contains("\n") || mimetype.contains("\r")) {
+			throw new IllegalArgumentException(
+					"mimetype can't contain newlines");
+		}
+		if (!mimetype.contains("/")) {
+			throw new IllegalArgumentException("Invalid mimetype: " + mimetype);
+		}
+		Path root = bundle.getRoot();
+
+		Path mimetypePath = bundle.getRoot().resolve(
+				BundleFileSystemProvider.MIMETYPE_FILE);
+		if (!Files.isRegularFile(mimetypePath)) {
+			// It would require low-level zip-modification to properly add
+			// 'mimetype' now
+			throw new IOException("Special file '"
+					+ BundleFileSystemProvider.MIMETYPE_FILE
+					+ "' missing from bundle, can't set mimetype");
+		}
+		setStringValue(mimetypePath, mimetype);
+	}
+
 	public static Path setReference(Path path, URI ref) throws IOException {
 		path = withExtension(path, DOT_URL);
 
@@ -317,6 +364,15 @@
 				StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE);
 	}
 
+	public static Path uriToBundlePath(Bundle bundle, URI uri) {
+		URI rootUri = bundle.getRoot().toUri();
+		uri = relativizeFromBase(uri, rootUri);
+		if (uri.isAbsolute() || uri.getFragment() != null) {
+			return null;
+		}
+		return bundle.getFileSystem().provider().getPath(rootUri.resolve(uri));
+	}
+
 	protected static Path withExtension(Path path, String extension) {
 		if (!extension.isEmpty() && !extension.startsWith(".")) {
 			throw new IllegalArgumentException(
@@ -332,60 +388,4 @@
 		return path.resolveSibling(newP);
 	}
 
-	public static Path getAnnotations(Bundle bundle) throws IOException {
-		Path dir = bundle.getFileSystem().getPath(DOT_RO, ANNOTATIONS);
-		Files.createDirectories(dir);
-		return dir;
-	}
-
-	public static Path getManifestPath(Bundle bundle) {
-		return bundle.getRoot().resolve(DOT_RO).resolve(MANIFEST_JSON);
-	}
-
-	public static String getMimeType(Bundle bundle) throws IOException {
-		Path mimetypePath = bundle.getRoot().resolve(
-				BundleFileSystemProvider.MIMETYPE_FILE);
-		String mimetype = getStringValue(mimetypePath);
-		if (mimetype == null || mimetype.isEmpty()) {
-			return BundleFileSystemProvider.APPLICATION_VND_WF4EVER_ROBUNDLE_ZIP;
-		}
-		return mimetype.trim();
-	}
-
-	public static void setMimeType(Bundle bundle, String mimetype)
-			throws IOException {
-		if (!ASCII.newEncoder().canEncode(mimetype)) {
-			throw new IllegalArgumentException("mimetype must be ASCII, not "
-					+ mimetype);
-		}
-		if (mimetype.contains("\n") || mimetype.contains("\r")) {
-			throw new IllegalArgumentException(
-					"mimetype can't contain newlines");
-		}
-		if (!mimetype.contains("/")) {
-			throw new IllegalArgumentException("Invalid mimetype: " + mimetype);
-		}
-		Path root = bundle.getRoot();
-
-		Path mimetypePath = bundle.getRoot().resolve(
-				BundleFileSystemProvider.MIMETYPE_FILE);
-		if (!Files.isRegularFile(mimetypePath)) {
-			// It would require low-level zip-modification to properly add
-			// 'mimetype' now
-			throw new IOException("Special file '"
-					+ BundleFileSystemProvider.MIMETYPE_FILE
-					+ "' missing from bundle, can't set mimetype");
-		}
-		setStringValue(mimetypePath, mimetype);
-	}
-
-	public static Path uriToBundlePath(Bundle bundle, URI uri) {
-		URI rootUri = bundle.getRoot().toUri();
-		uri = relativizeFromBase(uri, rootUri);
-		if (uri.isAbsolute() || uri.getFragment() != null) {
-			return null;
-		}
-		return bundle.getFileSystem().provider().getPath(rootUri.resolve(uri));
-	}
-
 }
diff --git a/src/main/java/org/purl/wf4ever/robundle/fs/BundleFileSystemProvider.java b/src/main/java/org/purl/wf4ever/robundle/fs/BundleFileSystemProvider.java
index 3aa0586..d8d5f76 100644
--- a/src/main/java/org/purl/wf4ever/robundle/fs/BundleFileSystemProvider.java
+++ b/src/main/java/org/purl/wf4ever/robundle/fs/BundleFileSystemProvider.java
@@ -49,8 +49,6 @@
 import org.purl.wf4ever.robundle.utils.TemporaryFiles;
 
 public class BundleFileSystemProvider extends FileSystemProvider {
-	public static final String MIMETYPE_FILE = "mimetype";
-
 	public class BundleFileChannel extends FileChannel {
 
 		@SuppressWarnings("unused")
@@ -153,6 +151,8 @@
 		private static final BundleFileSystemProvider INSTANCE = new BundleFileSystemProvider();
 	}
 
+	public static final String MIMETYPE_FILE = "mimetype";
+
 	public static final String APPLICATION_VND_WF4EVER_ROBUNDLE_ZIP = "application/vnd.wf4ever.robundle+zip";
 	/**
 	 * The list of open file systems. This is static so that it is shared across
@@ -262,6 +262,8 @@
 		return fs;
 	}
 
+	private Boolean jarDoubleEscaping;
+
 	/**
 	 * Public constructor provided for FileSystemProvider.installedProviders().
 	 * Use #getInstance() instead.
@@ -272,56 +274,14 @@
 	public BundleFileSystemProvider() {
 	}
 
-	private Boolean jarDoubleEscaping;
-
-	protected boolean getJarDoubleEscaping() {
-		if (jarDoubleEscaping != null) {
-			return jarDoubleEscaping;
+	private boolean asBoolean(Object object, boolean defaultValue) {
+		if (object instanceof Boolean) {
+			return (Boolean) object;
 		}
-		// https://bugs.openjdk.java.net/browse/JDK-8001178 introduced an
-		// inconsistent
-		// URI syntax. Before 7u40, jar: URIs to ZipFileSystemProvided had to
-		// have
-		// double-escaped the URI for the ZIP file, after 7u40 it is only
-		// escaped once.
-		// E.g.
-		// to open before 7u40 you needed
-		// jar:file:///file%2520with%2520spaces.zip, now you need
-		// jar:file:///file%20with%20spaces.zip
-		//
-		// The new format is now consistent with URL.openStream() and
-		// URLClassLoader's traditional jar: syntax, but somehow
-		// zippath.toUri() still returns the double-escaped one, which
-		// should only affects BundleFileSystem.findSource(). To help
-		// findSource()
-		// if this new bug is later fixed, we here detect which escaping style
-		// is used.
-
-		String name = "jar test";
-		try {
-			Path tmp = Files.createTempFile(name, ".zip");
-			if (!tmp.toUri().toASCIIString().contains("jar%20test")) {
-				// Hmm.. spaces not allowed in tmp? As we don't know, we'll
-				// assume Java 7 behaviour
-				jarDoubleEscaping = false;
-				return jarDoubleEscaping;
-			}
-			createBundleAsZip(tmp, null);
-			try (FileSystem fs = FileSystems.newFileSystem(tmp, null)) {
-				URI root = fs.getRootDirectories().iterator().next().toUri();
-				if (root.toASCIIString().contains("jar%2520test")) {
-					jarDoubleEscaping = true;
-				} else {
-					jarDoubleEscaping = false;
-				}
-			}
-			Files.delete(tmp);
-		} catch (IOException e) {
-			// Unknown error.. we'll assume Java 7 behaviour
-			jarDoubleEscaping = true;
+		if (object instanceof String) {
+			return Boolean.valueOf((String) object);
 		}
-		return jarDoubleEscaping;
-
+		return defaultValue;
 	}
 
 	protected URI baseURIFor(URI uri) {
@@ -426,6 +386,56 @@
 		}
 	}
 
+	protected boolean getJarDoubleEscaping() {
+		if (jarDoubleEscaping != null) {
+			return jarDoubleEscaping;
+		}
+		// https://bugs.openjdk.java.net/browse/JDK-8001178 introduced an
+		// inconsistent
+		// URI syntax. Before 7u40, jar: URIs to ZipFileSystemProvided had to
+		// have
+		// double-escaped the URI for the ZIP file, after 7u40 it is only
+		// escaped once.
+		// E.g.
+		// to open before 7u40 you needed
+		// jar:file:///file%2520with%2520spaces.zip, now you need
+		// jar:file:///file%20with%20spaces.zip
+		//
+		// The new format is now consistent with URL.openStream() and
+		// URLClassLoader's traditional jar: syntax, but somehow
+		// zippath.toUri() still returns the double-escaped one, which
+		// should only affects BundleFileSystem.findSource(). To help
+		// findSource()
+		// if this new bug is later fixed, we here detect which escaping style
+		// is used.
+
+		String name = "jar test";
+		try {
+			Path tmp = Files.createTempFile(name, ".zip");
+			if (!tmp.toUri().toASCIIString().contains("jar%20test")) {
+				// Hmm.. spaces not allowed in tmp? As we don't know, we'll
+				// assume Java 7 behaviour
+				jarDoubleEscaping = false;
+				return jarDoubleEscaping;
+			}
+			createBundleAsZip(tmp, null);
+			try (FileSystem fs = FileSystems.newFileSystem(tmp, null)) {
+				URI root = fs.getRootDirectories().iterator().next().toUri();
+				if (root.toASCIIString().contains("jar%2520test")) {
+					jarDoubleEscaping = true;
+				} else {
+					jarDoubleEscaping = false;
+				}
+			}
+			Files.delete(tmp);
+		} catch (IOException e) {
+			// Unknown error.. we'll assume Java 7 behaviour
+			jarDoubleEscaping = true;
+		}
+		return jarDoubleEscaping;
+
+	}
+
 	@Override
 	public Path getPath(URI uri) {
 		BundleFileSystem fs = getFileSystem(uri);
@@ -597,16 +607,6 @@
 		return fs;
 	}
 
-	private boolean asBoolean(Object object, boolean defaultValue) {
-		if (object instanceof Boolean) {
-			return (Boolean) object;
-		}
-		if (object instanceof String) {
-			return Boolean.valueOf((String) object);
-		}
-		return defaultValue;
-	}
-
 	@Override
 	public InputStream newInputStream(Path path, OpenOption... options)
 			throws IOException {
diff --git a/src/main/java/org/purl/wf4ever/robundle/manifest/Manifest.java b/src/main/java/org/purl/wf4ever/robundle/manifest/Manifest.java
index ac180ab..d5891ab 100644
--- a/src/main/java/org/purl/wf4ever/robundle/manifest/Manifest.java
+++ b/src/main/java/org/purl/wf4ever/robundle/manifest/Manifest.java
@@ -40,22 +40,22 @@
 		"aggregates", "annotations", "@graph" })
 public class Manifest {
 
-	private static final String MANIFEST_JSON = "manifest.json";
-
-	private static Logger logger = Logger.getLogger(Manifest.class
-			.getCanonicalName());
-
-	private static URI ROOT = URI.create("/");
+	public abstract class FileTimeMixin {
+		@JsonValue
+		public abstract String toString();
+	}
 
 	public abstract class PathMixin {
 		@JsonValue
 		public abstract String toString();
 	}
 
-	public abstract class FileTimeMixin {
-		@JsonValue
-		public abstract String toString();
-	}
+	private static final String MANIFEST_JSON = "manifest.json";
+
+	private static Logger logger = Logger.getLogger(Manifest.class
+			.getCanonicalName());
+
+	private static URI ROOT = URI.create("/");
 
 	private static final String META_INF = "/META-INF";
 	private static final String MIMETYPE = "/mimetype";
@@ -103,6 +103,28 @@
 		return new ArrayList<>(aggregates.values());
 	}
 
+	public PathMetadata getAggregation(Path file) {
+		URI fileUri = file.toUri();
+		return getAggregation(fileUri);
+	}
+
+	public PathMetadata getAggregation(URI uri) {
+		uri = relativeToBundleRoot(uri);
+		PathMetadata metadata = aggregates.get(uri);
+		if (metadata == null) {
+			metadata = new PathMetadata();
+			if (!uri.isAbsolute() && uri.getFragment() == null) {
+				Path path = Bundles.uriToBundlePath(bundle, uri);
+				metadata.setFile(path);
+				metadata.setMediatype(guessMediaType(path));
+			} else {
+				metadata.setUri(uri);
+			}
+			aggregates.put(uri, metadata);
+		}
+		return metadata;
+	}
+
 	public List<PathAnnotation> getAnnotations() {
 		return annotations;
 	}
@@ -116,6 +138,11 @@
 	}
 
 	@JsonIgnore
+	public URI getBaseURI() {
+		return getBundle().getRoot().toUri();
+	}
+
+	@JsonIgnore
 	public Bundle getBundle() {
 		return bundle;
 	}
@@ -130,11 +157,6 @@
 		return context;
 	}
 
-	@JsonIgnore
-	public URI getBaseURI() {
-		return getBundle().getRoot().toUri();
-	}
-
 	public Agent getCreatedBy() {
 		return createdBy;
 	}
@@ -292,6 +314,11 @@
 		}
 	}
 
+	public URI relativeToBundleRoot(URI uri) {
+		uri = ROOT.resolve(bundle.getRoot().toUri().relativize(uri));
+		return uri;
+	}
+
 	public void setAggregates(List<PathMetadata> aggregates) {
 		this.aggregates.clear();
 
@@ -359,6 +386,10 @@
 		this.manifest = manifest;
 	}
 
+	public void writeAsCombineManifest() throws IOException {
+		new CombineManifest(this).createManifestXML();
+	}
+
 	/**
 	 * Write as an RO Bundle JSON-LD manifest
 	 * 
@@ -403,35 +434,4 @@
 	public Path writeAsODFManifest() throws IOException {
 		return new ODFManifest(this).createManifestXML();
 	}
-
-	public PathMetadata getAggregation(Path file) {
-		URI fileUri = file.toUri();
-		return getAggregation(fileUri);
-	}
-
-	public PathMetadata getAggregation(URI uri) {
-		uri = relativeToBundleRoot(uri);
-		PathMetadata metadata = aggregates.get(uri);
-		if (metadata == null) {
-			metadata = new PathMetadata();
-			if (!uri.isAbsolute() && uri.getFragment() == null) {
-				Path path = Bundles.uriToBundlePath(bundle, uri);
-				metadata.setFile(path);
-				metadata.setMediatype(guessMediaType(path));
-			} else {
-				metadata.setUri(uri);
-			}
-			aggregates.put(uri, metadata);
-		}
-		return metadata;
-	}
-
-	public URI relativeToBundleRoot(URI uri) {
-		uri = ROOT.resolve(bundle.getRoot().toUri().relativize(uri));
-		return uri;
-	}
-
-	public void writeAsCombineManifest() throws IOException {
-		new CombineManifest(this).createManifestXML();
-	}
 }
diff --git a/src/main/java/org/purl/wf4ever/robundle/manifest/PathAnnotation.java b/src/main/java/org/purl/wf4ever/robundle/manifest/PathAnnotation.java
index 3a255ed..53828f6 100644
--- a/src/main/java/org/purl/wf4ever/robundle/manifest/PathAnnotation.java
+++ b/src/main/java/org/purl/wf4ever/robundle/manifest/PathAnnotation.java
@@ -16,6 +16,10 @@
 	private URI uri;
 	private URI content;
 
+	public void generateAnnotationId() {
+		setUri(URI.create("urn:uuid:" + UUID.randomUUID()));
+	}
+
 	@JsonIgnore
 	public URI getAbout() {
 		if (about.isEmpty()) {
@@ -47,19 +51,17 @@
 		return getUri();
 	}
 
-	public URI getUri() {
-		return uri;
-	}
-
 	public URI getContent() {
 		return content;
 	}
 
-	public void setAbout(URI about) {
-		this.about.clear();
-		if (about != null) {
-			this.about.add(about);
-		}
+	public URI getUri() {
+		return uri;
+	}
+
+	private URI relativizePath(Path path) {
+		return URI.create("/.ro/").relativize(
+				URI.create(path.toUri().getRawPath()));
 	}
 
 	public void setAbout(List<URI> about) {
@@ -69,8 +71,15 @@
 		this.about = about;
 	}
 
-	public void setUri(URI uri) {
-		this.uri = uri;
+	public void setAbout(Path path) {
+		setAbout(relativizePath(path));
+	}
+
+	public void setAbout(URI about) {
+		this.about.clear();
+		if (about != null) {
+			this.about.add(about);
+		}
 	}
 
 	@Deprecated
@@ -78,25 +87,16 @@
 		setUri(annotation);
 	}
 
+	public void setContent(Path path) {
+		this.content = relativizePath(path);
+	}
+
 	public void setContent(URI content) {
 		this.content = content;
 	}
 
-	public void generateAnnotationId() {
-		setUri(URI.create("urn:uuid:" + UUID.randomUUID()));
-	}
-
-	public void setAbout(Path path) {
-		setAbout(relativizePath(path));
-	}
-
-	private URI relativizePath(Path path) {
-		return URI.create("/.ro/").relativize(
-				URI.create(path.toUri().getRawPath()));
-	}
-
-	public void setContent(Path path) {
-		this.content = relativizePath(path);
+	public void setUri(URI uri) {
+		this.uri = uri;
 	}
 
 	@Override
diff --git a/src/main/java/org/purl/wf4ever/robundle/manifest/PathMetadata.java b/src/main/java/org/purl/wf4ever/robundle/manifest/PathMetadata.java
index 378f940..22c380c 100644
--- a/src/main/java/org/purl/wf4ever/robundle/manifest/PathMetadata.java
+++ b/src/main/java/org/purl/wf4ever/robundle/manifest/PathMetadata.java
@@ -38,6 +38,18 @@
 		setUri(URI.create(uriStr));
 	}
 
+	public List<Agent> getAuthoredBy() {
+		return authoredBy;
+	}
+
+	public FileTime getAuthoredOn() {
+		return authoredOn;
+	}
+
+	public Proxy getBundledAs() {
+		return bundledAs;
+	}
+
 	public URI getConformsTo() {
 		return conformsTo;
 	}
@@ -70,6 +82,15 @@
 	}
 
 	@JsonIgnore
+	public Proxy getOrCreateBundledAs() {
+		if (bundledAs == null) {
+			bundledAs = new Proxy();
+			setProxy();
+		}
+		return bundledAs;
+	}
+
+	@JsonIgnore
 	@Deprecated
 	public URI getProxy() {
 		Proxy bundledAs = getBundledAs();
@@ -83,6 +104,25 @@
 		return uri;
 	}
 
+	public void setAuthoredBy(List<Agent> authoredBy) {
+		if (authoredBy == null) {
+			throw new NullPointerException("authoredBy list can't be empty");
+		}
+		this.authoredBy = authoredBy;
+	}
+
+	public void setAuthoredOn(FileTime authoredOn) {
+		this.authoredOn = authoredOn;
+	}
+
+	public void setBundledAs(Proxy bundledAs) {
+		if (bundledAs == null) {
+			throw new NullPointerException(
+					"bundledAs can't be empty (try a new Proxy instance)");
+		}
+		this.bundledAs = bundledAs;
+	}
+
 	public void setConformsTo(URI conformsTo) {
 		this.conformsTo = conformsTo;
 	}
@@ -144,44 +184,4 @@
 		return "PathMetadata <null>";
 	}
 
-	public List<Agent> getAuthoredBy() {
-		return authoredBy;
-	}
-
-	public void setAuthoredBy(List<Agent> authoredBy) {
-		if (authoredBy == null) {
-			throw new NullPointerException("authoredBy list can't be empty");
-		}
-		this.authoredBy = authoredBy;
-	}
-
-	public FileTime getAuthoredOn() {
-		return authoredOn;
-	}
-
-	public void setAuthoredOn(FileTime authoredOn) {
-		this.authoredOn = authoredOn;
-	}
-
-	@JsonIgnore
-	public Proxy getOrCreateBundledAs() {
-		if (bundledAs == null) {
-			bundledAs = new Proxy();
-			setProxy();
-		}
-		return bundledAs;
-	}
-
-	public Proxy getBundledAs() {
-		return bundledAs;
-	}
-
-	public void setBundledAs(Proxy bundledAs) {
-		if (bundledAs == null) {
-			throw new NullPointerException(
-					"bundledAs can't be empty (try a new Proxy instance)");
-		}
-		this.bundledAs = bundledAs;
-	}
-
 }
diff --git a/src/main/java/org/purl/wf4ever/robundle/manifest/Proxy.java b/src/main/java/org/purl/wf4ever/robundle/manifest/Proxy.java
index b146fc7..88b279d 100644
--- a/src/main/java/org/purl/wf4ever/robundle/manifest/Proxy.java
+++ b/src/main/java/org/purl/wf4ever/robundle/manifest/Proxy.java
@@ -53,11 +53,11 @@
 		this.folder = folder;
 	}
 
-	public void setURI(URI uri) {
-		this.uri = uri;
-	}
-
 	public void setURI() {
 		setURI(URI.create("urn:uuid:" + UUID.randomUUID()));
 	}
+
+	public void setURI(URI uri) {
+		this.uri = uri;
+	}
 }
diff --git a/src/main/java/org/purl/wf4ever/robundle/manifest/RDFToManifest.java b/src/main/java/org/purl/wf4ever/robundle/manifest/RDFToManifest.java
index 3df1795..fe1687d 100644
--- a/src/main/java/org/purl/wf4ever/robundle/manifest/RDFToManifest.java
+++ b/src/main/java/org/purl/wf4ever/robundle/manifest/RDFToManifest.java
@@ -33,18 +33,37 @@
 
 public class RDFToManifest {
 
+	public static class ClosableIterable<T> implements AutoCloseable,
+			Iterable<T> {
+
+		private ExtendedIterator<T> iterator;
+
+		public ClosableIterable(ExtendedIterator<T> iterator) {
+			this.iterator = iterator;
+		}
+
+		@Override
+		public void close() {
+			iterator.close();
+		}
+
+		@Override
+		public ExtendedIterator<T> iterator() {
+			return iterator;
+		}
+	}
+
 	private static Logger logger = Logger.getLogger(RDFToManifest.class
 			.getCanonicalName());
 
 	static {
 		setCachedHttpClientInJsonLD();
 	}
-
 	private static final String PROV = "http://www.w3.org/ns/prov#";
 	private static final String PROV_O = "http://www.w3.org/ns/prov-o#";
 	private static final String FOAF_0_1 = "http://xmlns.com/foaf/0.1/";
-	private static final String PAV = "http://purl.org/pav/";
 
+	private static final String PAV = "http://purl.org/pav/";
 	private static final String DCT = "http://purl.org/dc/terms/";
 	private static final String RO = "http://purl.org/wf4ever/ro#";
 	private static final String BUNDLE = "http://purl.org/wf4ever/bundle#";
@@ -56,11 +75,51 @@
 	private static final String PAV_RDF = "/ontologies/pav.rdf";
 	private static final String PROV_O_RDF = "/ontologies/prov-o.rdf";
 	private static final String PROV_AQ_RDF = "/ontologies/prov-aq.rdf";
+	public static <T> ClosableIterable<T> iterate(ExtendedIterator<T> iterator) {
+		return new ClosableIterable<T>(iterator);
+	}
+	protected static Model jsonLdAsJenaModel(InputStream jsonIn, URI base)
+			throws IOException, RiotException {
+		Model model = ModelFactory.createDefaultModel();
+		RDFDataMgr.read(model, jsonIn, base.toASCIIString(), Lang.JSONLD);
+		return model;
+
+		//
+		// Object input = JSONUtils.fromInputStream(jsonIn);
+		// JSONLDTripleCallback callback = new JenaTripleCallback();
+		// Model model = (Model)JSONLD.toRDF(input, callback, new
+		// Options(base.toASCIIString()));
+		// return model;
+	}
+	protected static URI makeBaseURI() throws URISyntaxException {
+		return new URI("app", UUID.randomUUID().toString(), "/", (String) null);
+	}
+
+	/**
+	 * Use a JarCacheStorage so that our JSON-LD @context can be loaded from our
+	 * classpath and not require network connectivity
+	 * 
+	 */
+	protected static void setCachedHttpClientInJsonLD() {
+		// JarCacheStorage cacheStorage = new JarCacheStorage(
+		// RDFToManifest.class.getClassLoader());
+		// synchronized (DocumentLoader.class) {
+		// HttpClient oldHttpClient = DocumentLoader.getHttpClient();
+		// CachingHttpClient wrappedHttpClient = new CachingHttpClient(
+		// oldHttpClient, cacheStorage, cacheStorage.getCacheConfig());
+		// DocumentLoader.setHttpClient(wrappedHttpClient);
+		// }
+		// synchronized (JSONUtils.class) {
+		// HttpClient oldHttpClient = JSONUtilsSub.getHttpClient();
+		// CachingHttpClient wrappedHttpClient = new CachingHttpClient(
+		// oldHttpClient, cacheStorage, cacheStorage.getCacheConfig());
+		// JSONUtilsSub.setHttpClient(wrappedHttpClient);
+		// }
+	}
 	private OntModel ore;
 	private ObjectProperty aggregates;
 	private ObjectProperty proxyFor;
 	private ObjectProperty proxyIn;
-
 	private OntClass aggregation;
 	private OntModel foaf;
 	private DatatypeProperty foafName;
@@ -70,29 +129,164 @@
 	private OntModel provaq;
 	private ObjectProperty hasProvenance;
 	private OntModel dct;
+
 	private ObjectProperty conformsTo;
+
 	private OntClass standard;
+
 	private ObjectProperty authoredBy;
+
 	private DatatypeProperty createdOn;
 	private DatatypeProperty authoredOn;
-
 	private DatatypeProperty format;
-
 	private OntModel oa;
-
 	private ObjectProperty hasBody;
-
 	private ObjectProperty hasTarget;
+
 	private ObjectProperty isDescribedBy;
+
 	private OntModel bundle;
+
 	private ObjectProperty hasProxy;
+
 	private ObjectProperty inFolder;
+
 	private ObjectProperty hasAnnotation;
 
 	public RDFToManifest() {
 		loadOntologies();
 	}
 
+	private void checkNotNull(Object... possiblyNulls) {
+		int i = 0;
+		for (Object check : possiblyNulls) {
+			if (check == null) {
+				throw new IllegalStateException("Could not load item #" + i);
+			}
+			i++;
+		}
+
+	}
+
+	private Individual findRO(OntModel model, URI base) {
+		try (ClosableIterable<? extends OntResource> instances = iterate(aggregation
+				.listInstances())) {
+			for (OntResource o : instances) {
+				// System.out.println("Woo " + o);
+				return o.asIndividual();
+			}
+		}
+		// Fallback - resolve as "/"
+		// TODO: Ensure it's an Aggregation?
+		return model.getIndividual(base.toString());
+	}
+
+	private List<Agent> getAgents(URI base, Individual in,
+			ObjectProperty property) {
+		List<Agent> creators = new ArrayList<>();
+		for (Individual agent : listObjectProperties(in, property)) {
+			Agent a = new Agent();
+			if (agent.getURI() != null) {
+				a.setUri(relativizeFromBase(agent.getURI(), base));
+			}
+
+			RDFNode name = agent.getPropertyValue(foafName);
+			if (name != null && name.isLiteral()) {
+				a.setName(name.asLiteral().getLexicalForm());
+			}
+			creators.add(a);
+		}
+		return creators;
+	}
+
+	protected OntModel getOntModel() {
+		OntModel ontModel = ModelFactory
+				.createOntologyModel(OntModelSpec.OWL_DL_MEM_RULE_INF);
+		ontModel.setNsPrefix("foaf", FOAF_0_1);
+		ontModel.setNsPrefix("prov", PROV);
+		ontModel.setNsPrefix("ore", ORE);
+		ontModel.setNsPrefix("pav", PAV);
+		ontModel.setNsPrefix("dct", DCT);
+		// ontModel.getDocumentManager().loadImports(foaf.getOntModel());
+		return ontModel;
+	}
+
+	private Set<Individual> listObjectProperties(OntResource ontResource,
+			ObjectProperty prop) {
+		LinkedHashSet<Individual> results = new LinkedHashSet<>();
+		try (ClosableIterable<RDFNode> props = iterate(ontResource
+				.listPropertyValues(prop))) {
+			for (RDFNode node : props) {
+				if (!node.isResource() || !node.canAs(Individual.class)) {
+					continue;
+				}
+				results.add(node.as(Individual.class));
+			}
+		}
+		return results;
+	}
+
+	protected synchronized void loadBundle() {
+		if (bundle != null) {
+			return;
+		}
+		OntModel ontModel = loadOntologyFromClasspath(BUNDLE_RDF, BUNDLE);
+		hasProxy = ontModel.getObjectProperty(BUNDLE + "hasProxy");
+		hasAnnotation = ontModel.getObjectProperty(BUNDLE + "hasAnnotation");
+		inFolder = ontModel.getObjectProperty(BUNDLE + "inFolder");
+		checkNotNull(hasProxy, hasAnnotation, inFolder);
+		bundle = ontModel;
+	}
+
+	protected synchronized void loadDCT() {
+		if (dct != null) {
+			return;
+		}
+
+		OntModel ontModel = loadOntologyFromClasspath(
+				"/ontologies/dcterms_od.owl",
+				"http://purl.org/wf4ever/dcterms_od");
+
+		// properties from dct
+		standard = ontModel.getOntClass(DCT + "Standard");
+		conformsTo = ontModel.getObjectProperty(DCT + "conformsTo");
+
+		// We'll cheat dc:format in
+		format = ontModel
+				.createDatatypeProperty("http://purl.org/dc/elements/1.1/"
+						+ "format");
+		checkNotNull(standard, conformsTo, format);
+
+		dct = ontModel;
+
+	}
+
+	//
+	protected synchronized void loadFOAF() {
+		if (foaf != null) {
+			return;
+		}
+
+		OntModel ontModel = loadOntologyFromClasspath(FOAF_RDF, FOAF_0_1);
+
+		// properties from foaf
+		foafName = ontModel.getDatatypeProperty(FOAF_0_1 + "name");
+		checkNotNull(foafName);
+
+		foaf = ontModel;
+	}
+
+	protected synchronized void loadOA() {
+		if (oa != null) {
+			return;
+		}
+		OntModel ontModel = loadOntologyFromClasspath(OA_RDF, OA);
+		hasTarget = ontModel.getObjectProperty(OA + "hasTarget");
+		hasBody = ontModel.getObjectProperty(OA + "hasBody");
+		checkNotNull(hasTarget, hasBody);
+		oa = ontModel;
+	}
+
 	protected void loadOntologies() {
 		loadDCT();
 		loadORE();
@@ -117,166 +311,6 @@
 		return ontModel;
 	}
 
-	protected static Model jsonLdAsJenaModel(InputStream jsonIn, URI base)
-			throws IOException, RiotException {
-		Model model = ModelFactory.createDefaultModel();
-		RDFDataMgr.read(model, jsonIn, base.toASCIIString(), Lang.JSONLD);
-		return model;
-
-		//
-		// Object input = JSONUtils.fromInputStream(jsonIn);
-		// JSONLDTripleCallback callback = new JenaTripleCallback();
-		// Model model = (Model)JSONLD.toRDF(input, callback, new
-		// Options(base.toASCIIString()));
-		// return model;
-	}
-
-	/**
-	 * Use a JarCacheStorage so that our JSON-LD @context can be loaded from our
-	 * classpath and not require network connectivity
-	 * 
-	 */
-	protected static void setCachedHttpClientInJsonLD() {
-		// JarCacheStorage cacheStorage = new JarCacheStorage(
-		// RDFToManifest.class.getClassLoader());
-		// synchronized (DocumentLoader.class) {
-		// HttpClient oldHttpClient = DocumentLoader.getHttpClient();
-		// CachingHttpClient wrappedHttpClient = new CachingHttpClient(
-		// oldHttpClient, cacheStorage, cacheStorage.getCacheConfig());
-		// DocumentLoader.setHttpClient(wrappedHttpClient);
-		// }
-		// synchronized (JSONUtils.class) {
-		// HttpClient oldHttpClient = JSONUtilsSub.getHttpClient();
-		// CachingHttpClient wrappedHttpClient = new CachingHttpClient(
-		// oldHttpClient, cacheStorage, cacheStorage.getCacheConfig());
-		// JSONUtilsSub.setHttpClient(wrappedHttpClient);
-		// }
-	}
-
-	private void checkNotNull(Object... possiblyNulls) {
-		int i = 0;
-		for (Object check : possiblyNulls) {
-			if (check == null) {
-				throw new IllegalStateException("Could not load item #" + i);
-			}
-			i++;
-		}
-
-	}
-
-	protected OntModel getOntModel() {
-		OntModel ontModel = ModelFactory
-				.createOntologyModel(OntModelSpec.OWL_DL_MEM_RULE_INF);
-		ontModel.setNsPrefix("foaf", FOAF_0_1);
-		ontModel.setNsPrefix("prov", PROV);
-		ontModel.setNsPrefix("ore", ORE);
-		ontModel.setNsPrefix("pav", PAV);
-		ontModel.setNsPrefix("dct", DCT);
-		// ontModel.getDocumentManager().loadImports(foaf.getOntModel());
-		return ontModel;
-	}
-
-	//
-	protected synchronized void loadFOAF() {
-		if (foaf != null) {
-			return;
-		}
-
-		OntModel ontModel = loadOntologyFromClasspath(FOAF_RDF, FOAF_0_1);
-
-		// properties from foaf
-		foafName = ontModel.getDatatypeProperty(FOAF_0_1 + "name");
-		checkNotNull(foafName);
-
-		foaf = ontModel;
-	}
-
-	protected synchronized void loadPAV() {
-		if (pav != null) {
-			return;
-		}
-
-		OntModel ontModel = loadOntologyFromClasspath(PAV_RDF, PAV);
-		// properties from foaf
-		createdBy = ontModel.getObjectProperty(PAV + "createdBy");
-		createdOn = ontModel.getDatatypeProperty(PAV + "createdOn");
-		authoredBy = ontModel.getObjectProperty(PAV + "authoredBy");
-		authoredOn = ontModel.getDatatypeProperty(PAV + "authoredOn");
-		checkNotNull(createdBy, createdOn, authoredBy, authoredOn);
-
-		pav = ontModel;
-	}
-
-	protected synchronized void loadPROVO() {
-		if (prov != null) {
-			return;
-		}
-		OntModel ontModel = loadOntologyFromClasspath(PROV_O_RDF, PROV_O);
-
-		checkNotNull(ontModel);
-
-		prov = ontModel;
-	}
-
-	protected synchronized void loadPROVAQ() {
-		if (provaq != null) {
-			return;
-		}
-		OntModel ontModel = loadOntologyFromClasspath(PROV_AQ_RDF, PAV);
-
-		// properties from foaf
-		hasProvenance = ontModel.getObjectProperty(PROV + "has_provenance");
-		checkNotNull(hasProvenance);
-
-		provaq = ontModel;
-	}
-
-	protected synchronized void loadDCT() {
-		if (dct != null) {
-			return;
-		}
-
-		OntModel ontModel = loadOntologyFromClasspath(
-				"/ontologies/dcterms_od.owl",
-				"http://purl.org/wf4ever/dcterms_od");
-
-		// properties from dct
-		standard = ontModel.getOntClass(DCT + "Standard");
-		conformsTo = ontModel.getObjectProperty(DCT + "conformsTo");
-
-		// We'll cheat dc:format in
-		format = ontModel
-				.createDatatypeProperty("http://purl.org/dc/elements/1.1/"
-						+ "format");
-		checkNotNull(standard, conformsTo, format);
-
-		dct = ontModel;
-
-	}
-
-	protected synchronized void loadOA() {
-		if (oa != null) {
-			return;
-		}
-		OntModel ontModel = loadOntologyFromClasspath(OA_RDF, OA);
-		hasTarget = ontModel.getObjectProperty(OA + "hasTarget");
-		hasBody = ontModel.getObjectProperty(OA + "hasBody");
-		checkNotNull(hasTarget, hasBody);
-		oa = ontModel;
-	}
-
-	protected synchronized void loadBundle() {
-		if (bundle != null) {
-			return;
-		}
-		OntModel ontModel = loadOntologyFromClasspath(BUNDLE_RDF, BUNDLE);
-		hasProxy = ontModel.getObjectProperty(BUNDLE + "hasProxy");
-		hasAnnotation = ontModel.getObjectProperty(BUNDLE + "hasAnnotation");
-		inFolder = ontModel.getObjectProperty(BUNDLE + "inFolder");
-		checkNotNull(hasProxy, hasAnnotation, inFolder);
-		bundle = ontModel;
-	}
-
 	protected synchronized void loadORE() {
 		if (ore != null) {
 			return;
@@ -295,28 +329,44 @@
 		ore = ontModel;
 	}
 
-	public static <T> ClosableIterable<T> iterate(ExtendedIterator<T> iterator) {
-		return new ClosableIterable<T>(iterator);
+	protected synchronized void loadPAV() {
+		if (pav != null) {
+			return;
+		}
+
+		OntModel ontModel = loadOntologyFromClasspath(PAV_RDF, PAV);
+		// properties from foaf
+		createdBy = ontModel.getObjectProperty(PAV + "createdBy");
+		createdOn = ontModel.getDatatypeProperty(PAV + "createdOn");
+		authoredBy = ontModel.getObjectProperty(PAV + "authoredBy");
+		authoredOn = ontModel.getDatatypeProperty(PAV + "authoredOn");
+		checkNotNull(createdBy, createdOn, authoredBy, authoredOn);
+
+		pav = ontModel;
 	}
 
-	public static class ClosableIterable<T> implements AutoCloseable,
-			Iterable<T> {
-
-		private ExtendedIterator<T> iterator;
-
-		public ClosableIterable(ExtendedIterator<T> iterator) {
-			this.iterator = iterator;
+	protected synchronized void loadPROVAQ() {
+		if (provaq != null) {
+			return;
 		}
+		OntModel ontModel = loadOntologyFromClasspath(PROV_AQ_RDF, PAV);
 
-		@Override
-		public void close() {
-			iterator.close();
-		}
+		// properties from foaf
+		hasProvenance = ontModel.getObjectProperty(PROV + "has_provenance");
+		checkNotNull(hasProvenance);
 
-		@Override
-		public ExtendedIterator<T> iterator() {
-			return iterator;
+		provaq = ontModel;
+	}
+
+	protected synchronized void loadPROVO() {
+		if (prov != null) {
+			return;
 		}
+		OntModel ontModel = loadOntologyFromClasspath(PROV_O_RDF, PROV_O);
+
+		checkNotNull(ontModel);
+
+		prov = ontModel;
 	}
 
 	public void readTo(InputStream manifestResourceAsStream, Manifest manifest,
@@ -461,54 +511,4 @@
 
 	}
 
-	private List<Agent> getAgents(URI base, Individual in,
-			ObjectProperty property) {
-		List<Agent> creators = new ArrayList<>();
-		for (Individual agent : listObjectProperties(in, property)) {
-			Agent a = new Agent();
-			if (agent.getURI() != null) {
-				a.setUri(relativizeFromBase(agent.getURI(), base));
-			}
-
-			RDFNode name = agent.getPropertyValue(foafName);
-			if (name != null && name.isLiteral()) {
-				a.setName(name.asLiteral().getLexicalForm());
-			}
-			creators.add(a);
-		}
-		return creators;
-	}
-
-	protected static URI makeBaseURI() throws URISyntaxException {
-		return new URI("app", UUID.randomUUID().toString(), "/", (String) null);
-	}
-
-	private Set<Individual> listObjectProperties(OntResource ontResource,
-			ObjectProperty prop) {
-		LinkedHashSet<Individual> results = new LinkedHashSet<>();
-		try (ClosableIterable<RDFNode> props = iterate(ontResource
-				.listPropertyValues(prop))) {
-			for (RDFNode node : props) {
-				if (!node.isResource() || !node.canAs(Individual.class)) {
-					continue;
-				}
-				results.add(node.as(Individual.class));
-			}
-		}
-		return results;
-	}
-
-	private Individual findRO(OntModel model, URI base) {
-		try (ClosableIterable<? extends OntResource> instances = iterate(aggregation
-				.listInstances())) {
-			for (OntResource o : instances) {
-				// System.out.println("Woo " + o);
-				return o.asIndividual();
-			}
-		}
-		// Fallback - resolve as "/"
-		// TODO: Ensure it's an Aggregation?
-		return model.getIndividual(base.toString());
-	}
-
 }
diff --git a/src/main/java/org/purl/wf4ever/robundle/manifest/combine/CombineManifest.java b/src/main/java/org/purl/wf4ever/robundle/manifest/combine/CombineManifest.java
index ed0a58c..f1871e1 100644
--- a/src/main/java/org/purl/wf4ever/robundle/manifest/combine/CombineManifest.java
+++ b/src/main/java/org/purl/wf4ever/robundle/manifest/combine/CombineManifest.java
@@ -58,14 +58,14 @@
  */
 public class CombineManifest {
 
-	private static final URI OMEX_METADATA = URI
-			.create("http://identifiers.org/combine.specifications/omex-metadata");
-
-	private static final String MANIFEST_XML = "manifest.xml";
-
 	public static class ManifestNamespacePrefixMapperJAXB_RI extends
 			NamespacePrefixMapper {
 		@Override
+		public String[] getPreDeclaredNamespaceUris() {
+			return new String[] { OMEX_METADATA.toString() };
+		}
+
+		@Override
 		public String getPreferredPrefix(String namespaceUri,
 				String suggestion, boolean requirePrefix) {
 			if (namespaceUri.equals(OMEX_METADATA.toString())) {
@@ -74,151 +74,159 @@
 			return suggestion;
 		}
 
-		@Override
-		public String[] getPreDeclaredNamespaceUris() {
-			return new String[] { OMEX_METADATA.toString() };
-		}
-
 	}
 
+	private static final URI OMEX_METADATA = URI
+			.create("http://identifiers.org/combine.specifications/omex-metadata");
+
+	private static final String MANIFEST_XML = "manifest.xml";
+
 	private static Logger logger = Logger.getLogger(CombineManifest.class
 			.getCanonicalName());
 
+	public static boolean containsManifest(Bundle bundle) {
+		return Files.isRegularFile(manifestXmlPath(bundle));
+	}
 	private org.purl.wf4ever.robundle.manifest.Manifest manifest;
 	private Bundle bundle;
+
 	private static boolean warnedPrefixMapper;
 
 	private static ObjectFactory objectFactory = new ObjectFactory();
 
 	private static JAXBContext jaxbContext;
 
-	public CombineManifest(org.purl.wf4ever.robundle.manifest.Manifest manifest) {
-		this.manifest = manifest;
-		this.bundle = manifest.getBundle();
+	private static final String sparqlPrefixes = "PREFIX foaf:  <http://xmlns.com/foaf/0.1/> \n"
+			+ "PREFIX vcard: <http://www.w3.org/2006/vcard/ns#> \n"
+			+ "PREFIX rdfs:  <http://www.w3.org/2000/01/rdf-schema#> \n"
+			+ "PREFIX dct:   <http://purl.org/dc/terms/> \n";
+
+	protected static synchronized Marshaller createMarshaller()
+			throws JAXBException {
+		Marshaller marshaller = getJaxbContext().createMarshaller();
+		setPrefixMapper(marshaller);
+		return marshaller;
 	}
 
-	private OmexManifest makeOmexManifest() {
-		Path manifestXml = bundle.getRoot().resolve("manifest.xml");
-		OmexManifest omexManifest = objectFactory.createOmexManifest();
-
-		PathMetadata aggr = manifest.getAggregation(manifestXml);
-		if (aggr.getConformsTo() == null) {
-			// Add the manifest itself
-			aggr.setConformsTo(URI
-					.create("http://identifiers.org/combine.specifications/omex-manifest"));
-		}
-
-		for (PathMetadata metadata : manifest.getAggregates()) {
-			Content content = objectFactory.createContent();
-			Path file = metadata.getFile();
-
-			if (file == null) {
-				content.setLocation(metadata.getUri().toString());
-			} else {
-				Path relPath = metadata.getFile().relativize(bundle.getRoot());
-				content.setLocation("./" + relPath);
-			}
-			if (metadata.getMediatype() != null
-					&& !metadata.getMediatype().isEmpty()) {
-				content.setFormat(metadata.getMediatype());
-			} else if (metadata.getConformsTo() != null) {
-				content.setFormat(metadata.getConformsTo().toString());
-			} else {
-				// Binary fallback as 'format' is required attribute
-				content.setFormat("application/octet-stream");
-			}
-
-			// TODO: Handle 'master' attribute
-
-			omexManifest.getContent().add(content);
-
-		}
-		// TODO: Should we add .ro/manifest.json and .ro/* ?
-		return omexManifest;
+	protected static synchronized Unmarshaller createUnMarshaller()
+			throws JAXBException {
+		Unmarshaller unmarshaller = getJaxbContext().createUnmarshaller();
+		return unmarshaller;
 	}
 
-	public Path createManifestXML() throws IOException {
-		OmexManifest omexManifest = makeOmexManifest();
+	private static List<RDFNode> creatingAgentsFor(Resource r) {
+		logger.fine("Finding creator of " + r);
+		String queryStr = sparqlPrefixes + "SELECT ?agent WHERE { \n" + " { \n"
+				+ "  ?r dct:creator [ \n" + "	    rdfs:member ?agent \n"
+				+ "  ] \n" + " } UNION { \n" + "   ?r dct:creator ?agent .\n "
+				+ "   FILTER NOT EXISTS { ?agent rdfs:member ?member } \n"
+				+ " } \n" + "} \n";
+		logger.finer(QueryFactory.create(queryStr).toString());
+		QueryExecution qexec = QueryExecutionFactory.create(queryStr,
+				r.getModel());
+		QuerySolutionMap binding = new QuerySolutionMap();
+		binding.add("r", r);
+		qexec.setInitialBinding(binding);
+		ResultSet select = qexec.execSelect();
+		List<RDFNode> agents = new ArrayList<>();
 
-		Path manifestXml = manifestXmlPath(bundle);
-		Files.createDirectories(manifestXml.getParent());
-		try (OutputStream outStream = Files.newOutputStream(manifestXml)) {
-			try {
-				createMarshaller().marshal(omexManifest, outStream);
-			} catch (JAXBException e) {
-				throw new RuntimeException("Could not serialize OMEX Manifest",
-						e);
-			}
+		while (select.hasNext()) {
+			RDFNode agent = select.next().get("agent");
+			logger.fine("Found: " + agent);
+			agents.add(agent);
 		}
-		return manifestXml;
+		return agents;
 	}
 
-	public void readCombineArchive() throws IOException {
-		readManifestXML();
-		findAnnotations();
-
-	}
-
-	public void readManifestXML() throws IOException {
-		Path manifestXml = manifestXmlPath(bundle);
-		OmexManifest omexManifest;
-		try (InputStream inStream = Files.newInputStream(manifestXml)) {
-			InputSource src = new InputSource(inStream);
-			Source source = new SAXSource(src);
-			omexManifest = createUnMarshaller().unmarshal(source,
-					OmexManifest.class).getValue();
-			// omexManifest = (OmexManifest)
-			// createUnMarshaller().unmarshal(inStream);
-		} catch (JAXBException | ClassCastException e) {
-			// logger.warning("Could not parse " + manifestXml);
-			throw new IOException("Could not parse " + manifestXml, e);
+	protected static synchronized JAXBContext getJaxbContext()
+			throws JAXBException {
+		if (jaxbContext == null) {
+			jaxbContext = JAXBContext
+					.newInstance(org.identifiers.combine_specifications.omex_manifest.ObjectFactory.class);
 		}
-		if (!manifest.getManifest().contains(manifestXml)) {
-			manifest.getManifest().add(manifestXml);
-		}
-		for (Content c : omexManifest.getContent()) {
-			PathMetadata metadata;
-			if (c.getLocation().contains(":")) {
-				try {
-					URI uri = new URI(c.getLocation());
-					if (uri.isAbsolute()) {
-						metadata = manifest.getAggregation(uri);
-					} else {
-						logger.warning("Not an absolute URI, but contains :"
-								+ c.getLocation());
-						continue;
-					}
-				} catch (URISyntaxException e) {
-					logger.warning("Invalid URI " + c.getLocation());
-					continue;
-				}
-			} else {
-				Path path = bundle.getRoot().resolve(c.getLocation());
-				if (Files.exists(path)) {
-					metadata = manifest.getAggregation(path);
-				} else {
-					logger.warning(MANIFEST_XML + " listed relative path "
-							+ path + ", but it does not exist in bundle");
-					continue;
-				}
-			}
-
-			// Format - is it an URI or media type?
-			if (c.getFormat().contains(":")) {
-				metadata.setConformsTo(URI.create(c.getFormat()));
-			} else if (!c.getFormat().isEmpty()) {
-				metadata.setMediatype(c.getFormat());
-			} else if (metadata.getFile() != null) {
-				metadata.setMediatype(manifest.guessMediaType(metadata
-						.getFile()));
-			} // else: Not needed for URIs
-		}
+		return jaxbContext;
 	}
 
 	private static Path manifestXmlPath(Bundle bundle) {
 		return bundle.getRoot().resolve(MANIFEST_XML);
 	}
 
+	private static Resource mboxForAgent(Resource agentResource) {
+		logger.fine("Finding mbox of " + agentResource);
+		String queryStr = sparqlPrefixes + "SELECT ?mbox WHERE { \n"
+				+ "		{ ?agent foaf:mbox ?mbox } \n" + "	UNION  \n"
+				+ "		{ ?agent vcard:hasEmail ?mbox } \n" + "	UNION  \n"
+				+ "		{ ?agent vcard:email ?email .  \n"
+				+ "       BIND(IRI(CONCAT(\"mbox:\", ?email)) AS ?mbox) \n" // legacy
+				+ "	    } \n" + "} \n";
+		logger.finer(QueryFactory.create(queryStr).toString());
+		QueryExecution qexec = QueryExecutionFactory.create(queryStr,
+				agentResource.getModel());
+		QuerySolutionMap binding = new QuerySolutionMap();
+		binding.add("agent", agentResource);
+		qexec.setInitialBinding(binding);
+		ResultSet select = qexec.execSelect();
+		if (select.hasNext()) {
+			Resource mbox = select.next().getResource("mbox");
+			logger.fine("Found mbox: " + mbox);
+			return mbox;
+		}
+		logger.fine("mbox not found");
+		return null;
+	}
+
+	private static String nameForAgent(Resource agentResource) {
+		logger.fine("Finding name of " + agentResource);
+		String queryStr = sparqlPrefixes
+				+ "SELECT ?name WHERE { \n"
+				+ "		{ ?agent foaf:name ?name } \n"
+				+ "	UNION  \n"
+				+ "		{ ?agent vcard:fn ?name } \n"
+				+ "	UNION  \n"
+				+ "		{ ?agent vcard:FN ?name } \n"
+				+ // legacy
+				"	UNION  \n"
+				+ "		{ ?agent rdfs:label ?name } \n"
+				+ " UNION  \n"
+				+ "     { \n"
+				+ "         { ?agent vcard:n ?n } UNION { ?agent vcard:hasName ?n } \n"
+				+ "         ?n vcard:family-name ?family ; \n"
+				+ "            vcard:given-name ?given . \n"
+				+ "          BIND(CONCAT(?given, \" \", ?family) AS ?name) \n"
+				+ "     } \n" + " UNION \n" + "     { "
+				+ "         ?agent foaf:givenName ?given ; \n"
+				+ "                foaf:familyName ?family \n"
+				+ "          BIND(CONCAT(?given, \" \", ?family) AS ?name) \n"
+				+ "     } \n" + " UNION \n" + "     { "
+				+ "         ?agent foaf:firstName ?given ; \n"
+				+ "                foaf:surname ?family \n"
+				+ "          BIND(CONCAT(?given, \" \", ?family) AS ?name) \n"
+				+ "     } \n" + "	}  \n";
+		logger.finer(QueryFactory.create(queryStr).toString());
+		QueryExecution qexec = QueryExecutionFactory.create(queryStr,
+				agentResource.getModel());
+		QuerySolutionMap binding = new QuerySolutionMap();
+		binding.add("agent", agentResource);
+		qexec.setInitialBinding(binding);
+		ResultSet select = qexec.execSelect();
+		if (select.hasNext()) {
+			String name = select.next().getLiteral("name").getString();
+			logger.fine(name);
+			return name;
+		}
+		logger.fine("(null)");
+		return null;
+	}
+
+	private static Model parseRDF(Path metadata) throws IOException {
+		Model model = ModelFactory.createDefaultModel();
+		try (InputStream in = Files.newInputStream(metadata)) {
+			RDFDataMgr.read(model, in, metadata.toUri().toASCIIString(),
+					RDFLanguages.RDFXML);
+		}
+		return model;
+	}
+
 	protected static void setPrefixMapper(Marshaller marshaller) {
 		boolean setPrefixMapper = false;
 
@@ -244,30 +252,45 @@
 		}
 	}
 
-	protected static synchronized Marshaller createMarshaller()
-			throws JAXBException {
-		Marshaller marshaller = getJaxbContext().createMarshaller();
-		setPrefixMapper(marshaller);
-		return marshaller;
+	public CombineManifest(org.purl.wf4ever.robundle.manifest.Manifest manifest) {
+		this.manifest = manifest;
+		this.bundle = manifest.getBundle();
 	}
 
-	protected static synchronized Unmarshaller createUnMarshaller()
-			throws JAXBException {
-		Unmarshaller unmarshaller = getJaxbContext().createUnmarshaller();
-		return unmarshaller;
-	}
-
-	protected static synchronized JAXBContext getJaxbContext()
-			throws JAXBException {
-		if (jaxbContext == null) {
-			jaxbContext = JAXBContext
-					.newInstance(org.identifiers.combine_specifications.omex_manifest.ObjectFactory.class);
+	private Collection<URI> bundleSubjects() throws IOException {
+		Set<URI> subjects = new HashSet<>();
+		subjects.add(bundle.getRoot().toUri());
+		for (PathMetadata pathMetadata : manifest.getAggregates()) {
+			subjects.add(pathMetadata.getUri());
+			if (pathMetadata.getFile() != null) {
+				subjects.add(pathMetadata.getFile().toUri());
+			}
+			if (pathMetadata.getFolder() != null) {
+				subjects.add(pathMetadata.getFolder().toUri());
+			}
+			// subjects.add(pathMetadata.getProxy());
 		}
-		return jaxbContext;
+		for (PathAnnotation a : manifest.getAnnotations()) {
+			subjects.add(a.getUri());
+		}
+		subjects.remove(null);
+		return subjects;
 	}
 
-	public static boolean containsManifest(Bundle bundle) {
-		return Files.isRegularFile(manifestXmlPath(bundle));
+	public Path createManifestXML() throws IOException {
+		OmexManifest omexManifest = makeOmexManifest();
+
+		Path manifestXml = manifestXmlPath(bundle);
+		Files.createDirectories(manifestXml.getParent());
+		try (OutputStream outStream = Files.newOutputStream(manifestXml)) {
+			try {
+				createMarshaller().marshal(omexManifest, outStream);
+			} catch (JAXBException e) {
+				throw new RuntimeException("Could not serialize OMEX Manifest",
+						e);
+			}
+		}
+		return manifestXml;
 	}
 
 	private void findAnnotations() throws IOException {
@@ -385,129 +408,106 @@
 		}
 	}
 
-	private static List<RDFNode> creatingAgentsFor(Resource r) {
-		logger.fine("Finding creator of " + r);
-		String queryStr = sparqlPrefixes + "SELECT ?agent WHERE { \n" + " { \n"
-				+ "  ?r dct:creator [ \n" + "	    rdfs:member ?agent \n"
-				+ "  ] \n" + " } UNION { \n" + "   ?r dct:creator ?agent .\n "
-				+ "   FILTER NOT EXISTS { ?agent rdfs:member ?member } \n"
-				+ " } \n" + "} \n";
-		logger.finer(QueryFactory.create(queryStr).toString());
-		QueryExecution qexec = QueryExecutionFactory.create(queryStr,
-				r.getModel());
-		QuerySolutionMap binding = new QuerySolutionMap();
-		binding.add("r", r);
-		qexec.setInitialBinding(binding);
-		ResultSet select = qexec.execSelect();
-		List<RDFNode> agents = new ArrayList<>();
+	private OmexManifest makeOmexManifest() {
+		Path manifestXml = bundle.getRoot().resolve("manifest.xml");
+		OmexManifest omexManifest = objectFactory.createOmexManifest();
 
-		while (select.hasNext()) {
-			RDFNode agent = select.next().get("agent");
-			logger.fine("Found: " + agent);
-			agents.add(agent);
+		PathMetadata aggr = manifest.getAggregation(manifestXml);
+		if (aggr.getConformsTo() == null) {
+			// Add the manifest itself
+			aggr.setConformsTo(URI
+					.create("http://identifiers.org/combine.specifications/omex-manifest"));
 		}
-		return agents;
-	}
 
-	private static String nameForAgent(Resource agentResource) {
-		logger.fine("Finding name of " + agentResource);
-		String queryStr = sparqlPrefixes
-				+ "SELECT ?name WHERE { \n"
-				+ "		{ ?agent foaf:name ?name } \n"
-				+ "	UNION  \n"
-				+ "		{ ?agent vcard:fn ?name } \n"
-				+ "	UNION  \n"
-				+ "		{ ?agent vcard:FN ?name } \n"
-				+ // legacy
-				"	UNION  \n"
-				+ "		{ ?agent rdfs:label ?name } \n"
-				+ " UNION  \n"
-				+ "     { \n"
-				+ "         { ?agent vcard:n ?n } UNION { ?agent vcard:hasName ?n } \n"
-				+ "         ?n vcard:family-name ?family ; \n"
-				+ "            vcard:given-name ?given . \n"
-				+ "          BIND(CONCAT(?given, \" \", ?family) AS ?name) \n"
-				+ "     } \n" + " UNION \n" + "     { "
-				+ "         ?agent foaf:givenName ?given ; \n"
-				+ "                foaf:familyName ?family \n"
-				+ "          BIND(CONCAT(?given, \" \", ?family) AS ?name) \n"
-				+ "     } \n" + " UNION \n" + "     { "
-				+ "         ?agent foaf:firstName ?given ; \n"
-				+ "                foaf:surname ?family \n"
-				+ "          BIND(CONCAT(?given, \" \", ?family) AS ?name) \n"
-				+ "     } \n" + "	}  \n";
-		logger.finer(QueryFactory.create(queryStr).toString());
-		QueryExecution qexec = QueryExecutionFactory.create(queryStr,
-				agentResource.getModel());
-		QuerySolutionMap binding = new QuerySolutionMap();
-		binding.add("agent", agentResource);
-		qexec.setInitialBinding(binding);
-		ResultSet select = qexec.execSelect();
-		if (select.hasNext()) {
-			String name = select.next().getLiteral("name").getString();
-			logger.fine(name);
-			return name;
-		}
-		logger.fine("(null)");
-		return null;
-	}
+		for (PathMetadata metadata : manifest.getAggregates()) {
+			Content content = objectFactory.createContent();
+			Path file = metadata.getFile();
 
-	private static Resource mboxForAgent(Resource agentResource) {
-		logger.fine("Finding mbox of " + agentResource);
-		String queryStr = sparqlPrefixes + "SELECT ?mbox WHERE { \n"
-				+ "		{ ?agent foaf:mbox ?mbox } \n" + "	UNION  \n"
-				+ "		{ ?agent vcard:hasEmail ?mbox } \n" + "	UNION  \n"
-				+ "		{ ?agent vcard:email ?email .  \n"
-				+ "       BIND(IRI(CONCAT(\"mbox:\", ?email)) AS ?mbox) \n" // legacy
-				+ "	    } \n" + "} \n";
-		logger.finer(QueryFactory.create(queryStr).toString());
-		QueryExecution qexec = QueryExecutionFactory.create(queryStr,
-				agentResource.getModel());
-		QuerySolutionMap binding = new QuerySolutionMap();
-		binding.add("agent", agentResource);
-		qexec.setInitialBinding(binding);
-		ResultSet select = qexec.execSelect();
-		if (select.hasNext()) {
-			Resource mbox = select.next().getResource("mbox");
-			logger.fine("Found mbox: " + mbox);
-			return mbox;
-		}
-		logger.fine("mbox not found");
-		return null;
-	}
-
-	private static final String sparqlPrefixes = "PREFIX foaf:  <http://xmlns.com/foaf/0.1/> \n"
-			+ "PREFIX vcard: <http://www.w3.org/2006/vcard/ns#> \n"
-			+ "PREFIX rdfs:  <http://www.w3.org/2000/01/rdf-schema#> \n"
-			+ "PREFIX dct:   <http://purl.org/dc/terms/> \n";
-
-	private Collection<URI> bundleSubjects() throws IOException {
-		Set<URI> subjects = new HashSet<>();
-		subjects.add(bundle.getRoot().toUri());
-		for (PathMetadata pathMetadata : manifest.getAggregates()) {
-			subjects.add(pathMetadata.getUri());
-			if (pathMetadata.getFile() != null) {
-				subjects.add(pathMetadata.getFile().toUri());
+			if (file == null) {
+				content.setLocation(metadata.getUri().toString());
+			} else {
+				Path relPath = metadata.getFile().relativize(bundle.getRoot());
+				content.setLocation("./" + relPath);
 			}
-			if (pathMetadata.getFolder() != null) {
-				subjects.add(pathMetadata.getFolder().toUri());
+			if (metadata.getMediatype() != null
+					&& !metadata.getMediatype().isEmpty()) {
+				content.setFormat(metadata.getMediatype());
+			} else if (metadata.getConformsTo() != null) {
+				content.setFormat(metadata.getConformsTo().toString());
+			} else {
+				// Binary fallback as 'format' is required attribute
+				content.setFormat("application/octet-stream");
 			}
-			// subjects.add(pathMetadata.getProxy());
+
+			// TODO: Handle 'master' attribute
+
+			omexManifest.getContent().add(content);
+
 		}
-		for (PathAnnotation a : manifest.getAnnotations()) {
-			subjects.add(a.getUri());
-		}
-		subjects.remove(null);
-		return subjects;
+		// TODO: Should we add .ro/manifest.json and .ro/* ?
+		return omexManifest;
 	}
 
-	private static Model parseRDF(Path metadata) throws IOException {
-		Model model = ModelFactory.createDefaultModel();
-		try (InputStream in = Files.newInputStream(metadata)) {
-			RDFDataMgr.read(model, in, metadata.toUri().toASCIIString(),
-					RDFLanguages.RDFXML);
+	public void readCombineArchive() throws IOException {
+		readManifestXML();
+		findAnnotations();
+
+	}
+
+	public void readManifestXML() throws IOException {
+		Path manifestXml = manifestXmlPath(bundle);
+		OmexManifest omexManifest;
+		try (InputStream inStream = Files.newInputStream(manifestXml)) {
+			InputSource src = new InputSource(inStream);
+			Source source = new SAXSource(src);
+			omexManifest = createUnMarshaller().unmarshal(source,
+					OmexManifest.class).getValue();
+			// omexManifest = (OmexManifest)
+			// createUnMarshaller().unmarshal(inStream);
+		} catch (JAXBException | ClassCastException e) {
+			// logger.warning("Could not parse " + manifestXml);
+			throw new IOException("Could not parse " + manifestXml, e);
 		}
-		return model;
+		if (!manifest.getManifest().contains(manifestXml)) {
+			manifest.getManifest().add(manifestXml);
+		}
+		for (Content c : omexManifest.getContent()) {
+			PathMetadata metadata;
+			if (c.getLocation().contains(":")) {
+				try {
+					URI uri = new URI(c.getLocation());
+					if (uri.isAbsolute()) {
+						metadata = manifest.getAggregation(uri);
+					} else {
+						logger.warning("Not an absolute URI, but contains :"
+								+ c.getLocation());
+						continue;
+					}
+				} catch (URISyntaxException e) {
+					logger.warning("Invalid URI " + c.getLocation());
+					continue;
+				}
+			} else {
+				Path path = bundle.getRoot().resolve(c.getLocation());
+				if (Files.exists(path)) {
+					metadata = manifest.getAggregation(path);
+				} else {
+					logger.warning(MANIFEST_XML + " listed relative path "
+							+ path + ", but it does not exist in bundle");
+					continue;
+				}
+			}
+
+			// Format - is it an URI or media type?
+			if (c.getFormat().contains(":")) {
+				metadata.setConformsTo(URI.create(c.getFormat()));
+			} else if (!c.getFormat().isEmpty()) {
+				metadata.setMediatype(c.getFormat());
+			} else if (metadata.getFile() != null) {
+				metadata.setMediatype(manifest.guessMediaType(metadata
+						.getFile()));
+			} // else: Not needed for URIs
+		}
 	}
 
 }
diff --git a/src/main/java/org/purl/wf4ever/robundle/manifest/odf/ODFManifest.java b/src/main/java/org/purl/wf4ever/robundle/manifest/odf/ODFManifest.java
index e688fa4..adbe3d7 100644
--- a/src/main/java/org/purl/wf4ever/robundle/manifest/odf/ODFManifest.java
+++ b/src/main/java/org/purl/wf4ever/robundle/manifest/odf/ODFManifest.java
@@ -30,6 +30,12 @@
 	public static class ManifestNamespacePrefixMapperJAXB_RI extends
 			NamespacePrefixMapper {
 		@Override
+		public String[] getPreDeclaredNamespaceUris() {
+			// TODO Auto-generated method stub
+			return super.getPreDeclaredNamespaceUris();
+		}
+
+		@Override
 		public String getPreferredPrefix(String namespaceUri,
 				String suggestion, boolean requirePrefix) {
 			if (namespaceUri
@@ -39,12 +45,6 @@
 			return suggestion;
 		}
 
-		@Override
-		public String[] getPreDeclaredNamespaceUris() {
-			// TODO Auto-generated method stub
-			return super.getPreDeclaredNamespaceUris();
-		}
-
 	}
 
 	private static final String ODF_MANIFEST_VERSION = "1.2";
@@ -55,9 +55,151 @@
 			.getCanonicalName());
 
 	private static JAXBContext jaxbContext;
+	public static boolean containsManifest(Bundle bundle) {
+		return Files.isRegularFile(manifestXmlPath(bundle));
+	}
+	protected static synchronized Marshaller createMarshaller()
+			throws JAXBException {
+		Marshaller marshaller = getJaxbContext().createMarshaller();
+		setPrefixMapper(marshaller);
+		return marshaller;
+	}
+	protected static synchronized Unmarshaller createUnMarshaller()
+			throws JAXBException {
+		Unmarshaller unmarshaller = getJaxbContext().createUnmarshaller();
+		return unmarshaller;
+	}
+	protected static synchronized JAXBContext getJaxbContext()
+			throws JAXBException {
+		if (jaxbContext == null) {
+			jaxbContext = JAXBContext
+					.newInstance(oasis.names.tc.opendocument.xmlns.manifest._1.ObjectFactory.class
+					// ,
+					// org.oasis_open.names.tc.opendocument.xmlns.container.ObjectFactory.class,
+					// org.w3._2000._09.xmldsig_.ObjectFactory.class,
+					// org.w3._2001._04.xmlenc_.ObjectFactory.class
+					);
+		}
+		return jaxbContext;
+	}
+
+	private static Path manifestXmlPath(Bundle bundle) {
+		return bundle.getRoot().resolve(MANIFEST_XML);
+	}
+
+	protected static void setPrefixMapper(Marshaller marshaller) {
+		boolean setPrefixMapper = false;
+
+		try {
+			// This only works with JAXB RI, in which case we can set the
+			// namespace prefix mapper
+			Class.forName("com.sun.xml.bind.marshaller.NamespacePrefixMapper");
+			marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper",
+					new ManifestNamespacePrefixMapperJAXB_RI());
+			// Note: A similar mapper for the built-in java
+			// (com.sun.xml.bind.internal.namespacePrefixMapper)
+			// is no longer included here, as it will not (easily) compile with
+			// Maven.
+			setPrefixMapper = true;
+		} catch (Exception e) {
+			logger.log(Level.FINE, "Can't find NamespacePrefixMapper", e);
+		}
+
+		if (!setPrefixMapper && !warnedPrefixMapper) {
+			logger.info("Could not set prefix mapper (missing or incompatible JAXB) "
+					+ "- will use prefixes ns0, ns1, ..");
+			warnedPrefixMapper = true;
+		}
+	}
+
 	private org.purl.wf4ever.robundle.manifest.Manifest manifest;
+
 	private Bundle bundle;
+
+	// protected void prepareContainerXML() throws IOException {
+	//
+	//
+	// /* Check if we should prune <rootFiles> */
+	// Iterator<Object> iterator = containerXml.getValue().getRootFilesOrAny()
+	// .iterator();
+	// boolean foundAlready = false;
+	// while (iterator.hasNext()) {
+	// Object anyOrRoot = iterator.next();
+	// if (!(anyOrRoot instanceof JAXBElement)) {
+	// continue;
+	// }
+	// @SuppressWarnings("rawtypes")
+	// JAXBElement elem = (JAXBElement) anyOrRoot;
+	// if (!elem.getDeclaredType().equals(RootFiles.class)) {
+	// continue;
+	// }
+	// RootFiles rootFiles = (RootFiles) elem.getValue();
+	// if (foundAlready
+	// || (rootFiles.getOtherAttributes().isEmpty() && rootFiles
+	// .getAnyOrRootFile().isEmpty())) {
+	// // Delete it!
+	// System.err.println("Deleting unneccessary <rootFiles>");
+	// iterator.remove();
+	// }
+	// foundAlready = true;
+	// }
+	//
+	// Marshaller marshaller;
+	// OutputStream outStream = null;
+	// try {
+	// marshaller = createMarshaller();
+	// // XMLStreamWriter xmlStreamWriter = XMLOutputFactory
+	// // .newInstance().createXMLStreamWriter(outStream);
+	// // xmlStreamWriter.setDefaultNamespace(containerElem.getName()
+	// // .getNamespaceURI());
+	// //
+	// // xmlStreamWriter.setPrefix("dsig",
+	// // "http://www.w3.org/2000/09/xmldsig#");
+	// // xmlStreamWriter.setPrefix("xmlenc",
+	// // "http://www.w3.org/2001/04/xmlenc#");
+	// outStream = odfPackage.insertOutputStream(CONTAINER_XML);
+	//
+	// // FIXME: Set namespace prefixes and default namespace
+	//
+	// marshaller.setProperty("jaxb.formatted.output", true);
+	//
+	// // TODO: Ensure using default namespace
+	// marshaller.marshal(containerXml, outStream);
+	//
+	// } catch (IOException e) {
+	// throw e;
+	// } catch (Exception e) {
+	// throw new IOException("Could not parse " + CONTAINER_XML, e);
+	// } finally {
+	// if (outStream != null) {
+	// outStream.close();
+	// }
+	// }
+	// }
+	//
+	// @SuppressWarnings("unchecked")
+	// protected void parseContainerXML() throws IOException {
+	// createdContainerXml = false;
+	// InputStream containerStream = getResourceAsInputStream(CONTAINER_XML);
+	// if (containerStream == null) {
+	// // Make an empty containerXml
+	// Container container = containerFactory.createContainer();
+	// containerXml = containerFactory.createContainer(container);
+	// createdContainerXml = true;
+	// return;
+	// }
+	// try {
+	// Unmarshaller unMarshaller = createUnMarshaller();
+	// containerXml = (JAXBElement<Container>) unMarshaller
+	// .unmarshal(containerStream);
+	// } catch (JAXBException e) {
+	// throw new IOException("Could not parse " + CONTAINER_XML, e);
+	// }
+	//
+	// }
+
 	private ObjectFactory manifestFactory = new oasis.names.tc.opendocument.xmlns.manifest._1.ObjectFactory();
+
 	private static boolean warnedPrefixMapper;
 
 	public ODFManifest(org.purl.wf4ever.robundle.manifest.Manifest manifest) {
@@ -158,146 +300,4 @@
 		}
 	}
 
-	private static Path manifestXmlPath(Bundle bundle) {
-		return bundle.getRoot().resolve(MANIFEST_XML);
-	}
-
-	// protected void prepareContainerXML() throws IOException {
-	//
-	//
-	// /* Check if we should prune <rootFiles> */
-	// Iterator<Object> iterator = containerXml.getValue().getRootFilesOrAny()
-	// .iterator();
-	// boolean foundAlready = false;
-	// while (iterator.hasNext()) {
-	// Object anyOrRoot = iterator.next();
-	// if (!(anyOrRoot instanceof JAXBElement)) {
-	// continue;
-	// }
-	// @SuppressWarnings("rawtypes")
-	// JAXBElement elem = (JAXBElement) anyOrRoot;
-	// if (!elem.getDeclaredType().equals(RootFiles.class)) {
-	// continue;
-	// }
-	// RootFiles rootFiles = (RootFiles) elem.getValue();
-	// if (foundAlready
-	// || (rootFiles.getOtherAttributes().isEmpty() && rootFiles
-	// .getAnyOrRootFile().isEmpty())) {
-	// // Delete it!
-	// System.err.println("Deleting unneccessary <rootFiles>");
-	// iterator.remove();
-	// }
-	// foundAlready = true;
-	// }
-	//
-	// Marshaller marshaller;
-	// OutputStream outStream = null;
-	// try {
-	// marshaller = createMarshaller();
-	// // XMLStreamWriter xmlStreamWriter = XMLOutputFactory
-	// // .newInstance().createXMLStreamWriter(outStream);
-	// // xmlStreamWriter.setDefaultNamespace(containerElem.getName()
-	// // .getNamespaceURI());
-	// //
-	// // xmlStreamWriter.setPrefix("dsig",
-	// // "http://www.w3.org/2000/09/xmldsig#");
-	// // xmlStreamWriter.setPrefix("xmlenc",
-	// // "http://www.w3.org/2001/04/xmlenc#");
-	// outStream = odfPackage.insertOutputStream(CONTAINER_XML);
-	//
-	// // FIXME: Set namespace prefixes and default namespace
-	//
-	// marshaller.setProperty("jaxb.formatted.output", true);
-	//
-	// // TODO: Ensure using default namespace
-	// marshaller.marshal(containerXml, outStream);
-	//
-	// } catch (IOException e) {
-	// throw e;
-	// } catch (Exception e) {
-	// throw new IOException("Could not parse " + CONTAINER_XML, e);
-	// } finally {
-	// if (outStream != null) {
-	// outStream.close();
-	// }
-	// }
-	// }
-	//
-	// @SuppressWarnings("unchecked")
-	// protected void parseContainerXML() throws IOException {
-	// createdContainerXml = false;
-	// InputStream containerStream = getResourceAsInputStream(CONTAINER_XML);
-	// if (containerStream == null) {
-	// // Make an empty containerXml
-	// Container container = containerFactory.createContainer();
-	// containerXml = containerFactory.createContainer(container);
-	// createdContainerXml = true;
-	// return;
-	// }
-	// try {
-	// Unmarshaller unMarshaller = createUnMarshaller();
-	// containerXml = (JAXBElement<Container>) unMarshaller
-	// .unmarshal(containerStream);
-	// } catch (JAXBException e) {
-	// throw new IOException("Could not parse " + CONTAINER_XML, e);
-	// }
-	//
-	// }
-
-	protected static void setPrefixMapper(Marshaller marshaller) {
-		boolean setPrefixMapper = false;
-
-		try {
-			// This only works with JAXB RI, in which case we can set the
-			// namespace prefix mapper
-			Class.forName("com.sun.xml.bind.marshaller.NamespacePrefixMapper");
-			marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper",
-					new ManifestNamespacePrefixMapperJAXB_RI());
-			// Note: A similar mapper for the built-in java
-			// (com.sun.xml.bind.internal.namespacePrefixMapper)
-			// is no longer included here, as it will not (easily) compile with
-			// Maven.
-			setPrefixMapper = true;
-		} catch (Exception e) {
-			logger.log(Level.FINE, "Can't find NamespacePrefixMapper", e);
-		}
-
-		if (!setPrefixMapper && !warnedPrefixMapper) {
-			logger.info("Could not set prefix mapper (missing or incompatible JAXB) "
-					+ "- will use prefixes ns0, ns1, ..");
-			warnedPrefixMapper = true;
-		}
-	}
-
-	protected static synchronized Marshaller createMarshaller()
-			throws JAXBException {
-		Marshaller marshaller = getJaxbContext().createMarshaller();
-		setPrefixMapper(marshaller);
-		return marshaller;
-	}
-
-	protected static synchronized Unmarshaller createUnMarshaller()
-			throws JAXBException {
-		Unmarshaller unmarshaller = getJaxbContext().createUnmarshaller();
-		return unmarshaller;
-	}
-
-	protected static synchronized JAXBContext getJaxbContext()
-			throws JAXBException {
-		if (jaxbContext == null) {
-			jaxbContext = JAXBContext
-					.newInstance(oasis.names.tc.opendocument.xmlns.manifest._1.ObjectFactory.class
-					// ,
-					// org.oasis_open.names.tc.opendocument.xmlns.container.ObjectFactory.class,
-					// org.w3._2000._09.xmldsig_.ObjectFactory.class,
-					// org.w3._2001._04.xmlenc_.ObjectFactory.class
-					);
-		}
-		return jaxbContext;
-	}
-
-	public static boolean containsManifest(Bundle bundle) {
-		return Files.isRegularFile(manifestXmlPath(bundle));
-	}
-
 }
diff --git a/src/main/java/org/purl/wf4ever/robundle/utils/RecursiveCopyFileVisitor.java b/src/main/java/org/purl/wf4ever/robundle/utils/RecursiveCopyFileVisitor.java
index c05451a..5489e04 100644
--- a/src/main/java/org/purl/wf4ever/robundle/utils/RecursiveCopyFileVisitor.java
+++ b/src/main/java/org/purl/wf4ever/robundle/utils/RecursiveCopyFileVisitor.java
@@ -22,6 +22,15 @@
 
 public class RecursiveCopyFileVisitor extends SimpleFileVisitor<Path> {
 
+	public enum RecursiveCopyOption implements CopyOption {
+		/**
+		 * Ignore any errors, copy as much as possible. The default is to stop
+		 * on the first IOException.
+		 * 
+		 */
+		IGNORE_ERRORS,
+	}
+
 	public static void copyRecursively(final Path source,
 			final Path destination, final CopyOption... copyOptions)
 			throws IOException {
@@ -52,15 +61,6 @@
 		Files.walkFileTree(source, walkOptions, Integer.MAX_VALUE, visitor);
 	}
 
-	public enum RecursiveCopyOption implements CopyOption {
-		/**
-		 * Ignore any errors, copy as much as possible. The default is to stop
-		 * on the first IOException.
-		 * 
-		 */
-		IGNORE_ERRORS,
-	}
-
 	private final CopyOption[] copyOptions;
 	private final Set<CopyOption> copyOptionsSet;
 	private final Path destination;
@@ -94,6 +94,36 @@
 				.size())]);
 	}
 
+	private URI pathOnly(URI uri) {
+		if (!uri.isAbsolute()) {
+			return uri;
+		}
+		String path = uri.getRawPath();
+		// if (! uri.isOpaque()) {
+		// path = uri.getPath();
+		// }
+		if (uri.getScheme().equals("jar")) {
+			String part = uri.getSchemeSpecificPart();
+			int slashPos = part.indexOf("!/");
+			path = part.substring(slashPos + 1, part.length());
+		}
+		if (path == null) {
+			throw new IllegalArgumentException("Can't extract path from URI "
+					+ uri);
+		}
+
+		if (!path.startsWith("/")) {
+			path = "/" + path;
+		}
+		try {
+			return new URI(null, null, path, null);
+		} catch (URISyntaxException e) {
+			throw new IllegalArgumentException("Can't extract path from URI "
+					+ uri, e);
+		}
+
+	}
+
 	@Override
 	public FileVisitResult postVisitDirectory(Path dir, IOException exc)
 			throws IOException {
@@ -155,36 +185,6 @@
 		return destination.getFileSystem().provider().getPath(dest);
 	}
 
-	private URI pathOnly(URI uri) {
-		if (!uri.isAbsolute()) {
-			return uri;
-		}
-		String path = uri.getRawPath();
-		// if (! uri.isOpaque()) {
-		// path = uri.getPath();
-		// }
-		if (uri.getScheme().equals("jar")) {
-			String part = uri.getSchemeSpecificPart();
-			int slashPos = part.indexOf("!/");
-			path = part.substring(slashPos + 1, part.length());
-		}
-		if (path == null) {
-			throw new IllegalArgumentException("Can't extract path from URI "
-					+ uri);
-		}
-
-		if (!path.startsWith("/")) {
-			path = "/" + path;
-		}
-		try {
-			return new URI(null, null, path, null);
-		} catch (URISyntaxException e) {
-			throw new IllegalArgumentException("Can't extract path from URI "
-					+ uri, e);
-		}
-
-	}
-
 	private URI uriWithSlash(Path dir) {
 		URI uri = dir.toUri();
 		if (!uri.toString().endsWith("/")) {
diff --git a/src/main/java/org/purl/wf4ever/robundle/utils/RecursiveDeleteVisitor.java b/src/main/java/org/purl/wf4ever/robundle/utils/RecursiveDeleteVisitor.java
index b13d5fb..fe9a3fe 100644
--- a/src/main/java/org/purl/wf4ever/robundle/utils/RecursiveDeleteVisitor.java
+++ b/src/main/java/org/purl/wf4ever/robundle/utils/RecursiveDeleteVisitor.java
@@ -8,6 +8,14 @@
 import java.nio.file.attribute.BasicFileAttributes;
 
 public class RecursiveDeleteVisitor extends SimpleFileVisitor<Path> {
+	public static void deleteRecursively(Path p) throws IOException {
+		if (Files.isDirectory(p)) {
+			Files.walkFileTree(p, new RecursiveDeleteVisitor());
+		} else {
+			Files.delete(p);
+		}
+	}
+
 	@Override
 	public FileVisitResult postVisitDirectory(Path dir, IOException exc)
 			throws IOException {
@@ -22,12 +30,4 @@
 		Files.delete(file);
 		return FileVisitResult.CONTINUE;
 	}
-
-	public static void deleteRecursively(Path p) throws IOException {
-		if (Files.isDirectory(p)) {
-			Files.walkFileTree(p, new RecursiveDeleteVisitor());
-		} else {
-			Files.delete(p);
-		}
-	}
 }
\ No newline at end of file