You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by fa...@apache.org on 2021/05/22 20:22:17 UTC

svn commit: r1890119 [2/10] - in /poi/trunk/poi-ooxml/src: main/java/org/apache/poi/ooxml/extractor/ main/java/org/apache/poi/ooxml/util/ main/java/org/apache/poi/openxml4j/exceptions/ main/java/org/apache/poi/openxml4j/opc/ main/java/org/apache/poi/op...

Modified: poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/OPCPackage.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/OPCPackage.java?rev=1890119&r1=1890118&r2=1890119&view=diff
==============================================================================
--- poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/OPCPackage.java (original)
+++ poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/OPCPackage.java Sat May 22 20:22:16 2021
@@ -67,115 +67,115 @@ import org.apache.poi.util.NotImplemente
  */
 public abstract class OPCPackage implements RelationshipSource, Closeable {
 
-	/**
-	 * Logger.
-	 */
+    /**
+     * Logger.
+     */
     private static final Logger LOG = LogManager.getLogger(OPCPackage.class);
 
-	/**
-	 * Default package access.
-	 */
-	protected static final PackageAccess defaultPackageAccess = PackageAccess.READ_WRITE;
-
-	/**
-	 * Package access.
-	 */
-	private final PackageAccess packageAccess;
-
-	/**
-	 * Package parts collection.
-	 */
-	private PackagePartCollection partList;
-
-	/**
-	 * Package relationships.
-	 */
-	protected PackageRelationshipCollection relationships;
-
-	/**
-	 * Part marshallers by content type.
-	 */
-	protected final Map<ContentType, PartMarshaller> partMarshallers = new HashMap<>(5);
-
-	/**
-	 * Default part marshaller.
-	 */
-	protected final PartMarshaller defaultPartMarshaller = new DefaultMarshaller();
-
-	/**
-	 * Part unmarshallers by content type.
-	 */
-	protected final Map<ContentType, PartUnmarshaller> partUnmarshallers = new HashMap<>(2);
-
-	/**
-	 * Core package properties.
-	 */
-	protected PackagePropertiesPart packageProperties;
-
-	/**
-	 * Manage parts content types of this package.
-	 */
-	protected ContentTypeManager contentTypeManager;
-
-	/**
-	 * Flag if a modification is done to the document.
-	 */
-	protected boolean isDirty;
-
-	/**
-	 * File path of this package.
-	 */
-	protected String originalPackagePath;
-
-	/**
-	 * Output stream for writing this package.
-	 */
-	protected OutputStream output;
-
-	/**
-	 * Constructor.
-	 *
-	 * @param access
-	 *            Package access.
-	 */
-	OPCPackage(PackageAccess access) {
-		if (getClass() != ZipPackage.class) {
-			throw new IllegalArgumentException("PackageBase may not be subclassed");
-		}
-		this.packageAccess = access;
-
-		final ContentType contentType = newCorePropertiesPart();
-		// TODO Delocalize specialized marshallers
-		this.partUnmarshallers.put(contentType, new PackagePropertiesUnmarshaller());
-		this.partMarshallers.put(contentType, new ZipPackagePropertiesMarshaller());
-	}
-
-	private static ContentType newCorePropertiesPart() {
-		try {
-			return new ContentType(ContentTypes.CORE_PROPERTIES_PART);
-		} catch (InvalidFormatException e) {
-			// Should never happen
-			throw new OpenXML4JRuntimeException(
-				"Package.init() : this exception should never happen, " +
-				"if you read this message please send a mail to the developers team. : " +
-				e.getMessage(), e
-			);
-		}
-	}
-
-	/**
-	 * Open a package with read/write permission.
-	 *
-	 * @param path
-	 *            The document path.
-	 * @return A Package object, else <b>null</b>.
-	 * @throws InvalidFormatException
-	 *             If the specified file doesn't exist, and a parsing error
-	 *             occur.
-	 */
-	public static OPCPackage open(String path) throws InvalidFormatException {
-		return open(path, defaultPackageAccess);
-	}
+    /**
+     * Default package access.
+     */
+    protected static final PackageAccess defaultPackageAccess = PackageAccess.READ_WRITE;
+
+    /**
+     * Package access.
+     */
+    private final PackageAccess packageAccess;
+
+    /**
+     * Package parts collection.
+     */
+    private PackagePartCollection partList;
+
+    /**
+     * Package relationships.
+     */
+    protected PackageRelationshipCollection relationships;
+
+    /**
+     * Part marshallers by content type.
+     */
+    protected final Map<ContentType, PartMarshaller> partMarshallers = new HashMap<>(5);
+
+    /**
+     * Default part marshaller.
+     */
+    protected final PartMarshaller defaultPartMarshaller = new DefaultMarshaller();
+
+    /**
+     * Part unmarshallers by content type.
+     */
+    protected final Map<ContentType, PartUnmarshaller> partUnmarshallers = new HashMap<>(2);
+
+    /**
+     * Core package properties.
+     */
+    protected PackagePropertiesPart packageProperties;
+
+    /**
+     * Manage parts content types of this package.
+     */
+    protected ContentTypeManager contentTypeManager;
+
+    /**
+     * Flag if a modification is done to the document.
+     */
+    protected boolean isDirty;
+
+    /**
+     * File path of this package.
+     */
+    protected String originalPackagePath;
+
+    /**
+     * Output stream for writing this package.
+     */
+    protected OutputStream output;
+
+    /**
+     * Constructor.
+     *
+     * @param access
+     *            Package access.
+     */
+    OPCPackage(PackageAccess access) {
+        if (getClass() != ZipPackage.class) {
+            throw new IllegalArgumentException("PackageBase may not be subclassed");
+        }
+        this.packageAccess = access;
+
+        final ContentType contentType = newCorePropertiesPart();
+        // TODO Delocalize specialized marshallers
+        this.partUnmarshallers.put(contentType, new PackagePropertiesUnmarshaller());
+        this.partMarshallers.put(contentType, new ZipPackagePropertiesMarshaller());
+    }
+
+    private static ContentType newCorePropertiesPart() {
+        try {
+            return new ContentType(ContentTypes.CORE_PROPERTIES_PART);
+        } catch (InvalidFormatException e) {
+            // Should never happen
+            throw new OpenXML4JRuntimeException(
+                "Package.init() : this exception should never happen, " +
+                "if you read this message please send a mail to the developers team. : " +
+                e.getMessage(), e
+            );
+        }
+    }
+
+    /**
+     * Open a package with read/write permission.
+     *
+     * @param path
+     *            The document path.
+     * @return A Package object, else <b>null</b>.
+     * @throws InvalidFormatException
+     *             If the specified file doesn't exist, and a parsing error
+     *             occur.
+     */
+    public static OPCPackage open(String path) throws InvalidFormatException {
+        return open(path, defaultPackageAccess);
+    }
 
    /**
     * Open a package with read/write permission.
@@ -211,52 +211,52 @@ public abstract class OPCPackage impleme
            // pack.originalPackagePath = file.getAbsolutePath();
            return pack;
        } catch (InvalidFormatException | RuntimeException e) {
-		   IOUtils.closeQuietly(pack);
+           IOUtils.closeQuietly(pack);
            throw e;
        }
    }
 
-	/**
-	 * Open a package.
-	 *
-	 * @param path
-	 *            The document path.
-	 * @param access
-	 *            PackageBase access.
-	 * @return A PackageBase object, else <b>null</b>.
-	 * @throws InvalidFormatException
-	 *             If the specified file doesn't exist, and a parsing error
-	 *             occur.
-	 * @throws InvalidOperationException If the zip file cannot be opened.
-	 * @throws InvalidFormatException if the package is not valid.
-	 */
-	public static OPCPackage open(String path, PackageAccess access)
-			throws InvalidFormatException, InvalidOperationException {
-		if (path == null || path.trim().isEmpty()) {
-			throw new IllegalArgumentException("'path' must be given");
-		}
-
-		File file = new File(path);
-		if (file.exists() && file.isDirectory()) {
-			throw new IllegalArgumentException("path must not be a directory");
-		}
-
-		OPCPackage pack = new ZipPackage(path, access); // NOSONAR
-		boolean success = false;
-		if (pack.partList == null && access != PackageAccess.WRITE) {
-			try {
-				pack.getParts();
-				success = true;
-			} finally {
-				if (! success) {
-					IOUtils.closeQuietly(pack);
-				}
-			}
-		}
-
-		pack.originalPackagePath = new File(path).getAbsolutePath();
-		return pack;
-	}
+    /**
+     * Open a package.
+     *
+     * @param path
+     *            The document path.
+     * @param access
+     *            PackageBase access.
+     * @return A PackageBase object, else <b>null</b>.
+     * @throws InvalidFormatException
+     *             If the specified file doesn't exist, and a parsing error
+     *             occur.
+     * @throws InvalidOperationException If the zip file cannot be opened.
+     * @throws InvalidFormatException if the package is not valid.
+     */
+    public static OPCPackage open(String path, PackageAccess access)
+            throws InvalidFormatException, InvalidOperationException {
+        if (path == null || path.trim().isEmpty()) {
+            throw new IllegalArgumentException("'path' must be given");
+        }
+
+        File file = new File(path);
+        if (file.exists() && file.isDirectory()) {
+            throw new IllegalArgumentException("path must not be a directory");
+        }
+
+        OPCPackage pack = new ZipPackage(path, access); // NOSONAR
+        boolean success = false;
+        if (pack.partList == null && access != PackageAccess.WRITE) {
+            try {
+                pack.getParts();
+                success = true;
+            } finally {
+                if (! success) {
+                    IOUtils.closeQuietly(pack);
+                }
+            }
+        }
+
+        pack.originalPackagePath = new File(path).getAbsolutePath();
+        return pack;
+    }
 
    /**
     * Open a package.
@@ -280,200 +280,200 @@ public abstract class OPCPackage impleme
       }
 
       OPCPackage pack = new ZipPackage(file, access);
-	   try {
-		   if (pack.partList == null && access != PackageAccess.WRITE) {
-			   pack.getParts();
-		   }
-		   pack.originalPackagePath = file.getAbsolutePath();
-		   return pack;
-	   } catch (InvalidFormatException | RuntimeException e) {
-		   IOUtils.closeQuietly(pack);
-		   throw e;
-	   }
+       try {
+           if (pack.partList == null && access != PackageAccess.WRITE) {
+               pack.getParts();
+           }
+           pack.originalPackagePath = file.getAbsolutePath();
+           return pack;
+       } catch (InvalidFormatException | RuntimeException e) {
+           IOUtils.closeQuietly(pack);
+           throw e;
+       }
    }
 
-	/**
-	 * Open a package.
-	 *
-	 * Note - uses quite a bit more memory than {@link #open(String)}, which
-	 * doesn't need to hold the whole zip file in memory, and can take advantage
-	 * of native methods
-	 *
-	 * @param in
-	 *            The InputStream to read the package from
-	 * @return A PackageBase object
-	 *
-	 * @throws InvalidFormatException
-	 * 				Throws if the specified file exist and is not valid.
-	 * @throws IOException If reading the stream fails
-	 */
-	public static OPCPackage open(InputStream in) throws InvalidFormatException,
-			IOException {
-		OPCPackage pack = new ZipPackage(in, PackageAccess.READ_WRITE);
-		try {
-			if (pack.partList == null) {
-				pack.getParts();
-			}
-		} catch (InvalidFormatException | RuntimeException e) {
-			IOUtils.closeQuietly(pack);
-			throw e;
-		}
-		return pack;
-	}
-
-	/**
-	 * Opens a package if it exists, else it creates one.
-	 *
-	 * @param file
-	 *            The file to open or to create.
-	 * @return A newly created package if the specified file does not exist,
-	 *         else the package extract from the file.
-	 * @throws InvalidFormatException
-	 *             Throws if the specified file exist and is not valid.
-	 */
-	public static OPCPackage openOrCreate(File file) throws InvalidFormatException {
-		if (file.exists()) {
-			return open(file.getAbsolutePath());
-		} else {
-			return create(file);
-		}
-	}
-
-	/**
-	 * Creates a new package.
-	 *
-	 * @param path
-	 *            Path of the document.
-	 * @return A newly created PackageBase ready to use.
-	 */
-	public static OPCPackage create(String path) {
-		return create(new File(path));
-	}
-
-	/**
-	 * Creates a new package.
-	 *
-	 * @param file
-	 *            Path of the document.
-	 * @return A newly created PackageBase ready to use.
-	 */
-	public static OPCPackage create(File file) {
-		if (file == null || (file.exists() && file.isDirectory())) {
-			throw new IllegalArgumentException("file");
-		}
-
-		if (file.exists()) {
-			throw new InvalidOperationException(
-					"This package (or file) already exists : use the open() method or delete the file.");
-		}
-
-		// Creates a new package
-		OPCPackage pkg = new ZipPackage();
-		pkg.originalPackagePath = file.getAbsolutePath();
-
-		configurePackage(pkg);
-		return pkg;
-	}
-
-	public static OPCPackage create(OutputStream output) {
-		OPCPackage pkg = new ZipPackage();
-		pkg.originalPackagePath = null;
-		pkg.output = output;
-
-		configurePackage(pkg);
-		return pkg;
-	}
-
-	private static void configurePackage(OPCPackage pkg) {
-		try {
-			// Content type manager
-			pkg.contentTypeManager = new ZipContentTypeManager(null, pkg);
-
-			// Add default content types for .xml and .rels
-			pkg.contentTypeManager.addContentType(
-					PackagingURIHelper.createPartName(
-							PackagingURIHelper.PACKAGE_RELATIONSHIPS_ROOT_URI),
-					RELATIONSHIPS_PART);
-			pkg.contentTypeManager.addContentType(
-					PackagingURIHelper.createPartName("/default.xml"),
-					PLAIN_OLD_XML);
-
-			// Initialise some PackageBase properties
-			pkg.packageProperties = new PackagePropertiesPart(pkg,
-					PackagingURIHelper.CORE_PROPERTIES_PART_NAME);
-			pkg.packageProperties.setCreatorProperty("Generated by Apache POI OpenXML4J");
-			pkg.packageProperties.setCreatedProperty(Optional.of(new Date()));
-		} catch (InvalidFormatException e) {
-			// Should never happen
-			throw new IllegalStateException(e);
-		}
-	}
-
-	/**
-	 * Flush the package : save all.
-	 *
-	 * @see #close()
-	 */
-	public void flush() {
-		throwExceptionIfReadOnly();
-
-		if (this.packageProperties != null) {
-			this.packageProperties.flush();
-		}
-
-		this.flushImpl();
-	}
-
-	/**
-	 * Close the open, writable package and save its content.
-	 *
-	 * If your package is open read only, then you should call {@link #revert()}
-	 *  when finished with the package.
-	 *
-	 * This method is not thread-safe.
-	 *
-	 * @throws IOException
-	 *             If an IO exception occur during the saving process.
-	 */
-	@Override
+    /**
+     * Open a package.
+     *
+     * Note - uses quite a bit more memory than {@link #open(String)}, which
+     * doesn't need to hold the whole zip file in memory, and can take advantage
+     * of native methods
+     *
+     * @param in
+     *            The InputStream to read the package from
+     * @return A PackageBase object
+     *
+     * @throws InvalidFormatException
+     *              Throws if the specified file exist and is not valid.
+     * @throws IOException If reading the stream fails
+     */
+    public static OPCPackage open(InputStream in) throws InvalidFormatException,
+            IOException {
+        OPCPackage pack = new ZipPackage(in, PackageAccess.READ_WRITE);
+        try {
+            if (pack.partList == null) {
+                pack.getParts();
+            }
+        } catch (InvalidFormatException | RuntimeException e) {
+            IOUtils.closeQuietly(pack);
+            throw e;
+        }
+        return pack;
+    }
+
+    /**
+     * Opens a package if it exists, else it creates one.
+     *
+     * @param file
+     *            The file to open or to create.
+     * @return A newly created package if the specified file does not exist,
+     *         else the package extract from the file.
+     * @throws InvalidFormatException
+     *             Throws if the specified file exist and is not valid.
+     */
+    public static OPCPackage openOrCreate(File file) throws InvalidFormatException {
+        if (file.exists()) {
+            return open(file.getAbsolutePath());
+        } else {
+            return create(file);
+        }
+    }
+
+    /**
+     * Creates a new package.
+     *
+     * @param path
+     *            Path of the document.
+     * @return A newly created PackageBase ready to use.
+     */
+    public static OPCPackage create(String path) {
+        return create(new File(path));
+    }
+
+    /**
+     * Creates a new package.
+     *
+     * @param file
+     *            Path of the document.
+     * @return A newly created PackageBase ready to use.
+     */
+    public static OPCPackage create(File file) {
+        if (file == null || (file.exists() && file.isDirectory())) {
+            throw new IllegalArgumentException("file");
+        }
+
+        if (file.exists()) {
+            throw new InvalidOperationException(
+                    "This package (or file) already exists : use the open() method or delete the file.");
+        }
+
+        // Creates a new package
+        OPCPackage pkg = new ZipPackage();
+        pkg.originalPackagePath = file.getAbsolutePath();
+
+        configurePackage(pkg);
+        return pkg;
+    }
+
+    public static OPCPackage create(OutputStream output) {
+        OPCPackage pkg = new ZipPackage();
+        pkg.originalPackagePath = null;
+        pkg.output = output;
+
+        configurePackage(pkg);
+        return pkg;
+    }
+
+    private static void configurePackage(OPCPackage pkg) {
+        try {
+            // Content type manager
+            pkg.contentTypeManager = new ZipContentTypeManager(null, pkg);
+
+            // Add default content types for .xml and .rels
+            pkg.contentTypeManager.addContentType(
+                    PackagingURIHelper.createPartName(
+                            PackagingURIHelper.PACKAGE_RELATIONSHIPS_ROOT_URI),
+                    RELATIONSHIPS_PART);
+            pkg.contentTypeManager.addContentType(
+                    PackagingURIHelper.createPartName("/default.xml"),
+                    PLAIN_OLD_XML);
+
+            // Initialise some PackageBase properties
+            pkg.packageProperties = new PackagePropertiesPart(pkg,
+                    PackagingURIHelper.CORE_PROPERTIES_PART_NAME);
+            pkg.packageProperties.setCreatorProperty("Generated by Apache POI OpenXML4J");
+            pkg.packageProperties.setCreatedProperty(Optional.of(new Date()));
+        } catch (InvalidFormatException e) {
+            // Should never happen
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Flush the package : save all.
+     *
+     * @see #close()
+     */
+    public void flush() {
+        throwExceptionIfReadOnly();
+
+        if (this.packageProperties != null) {
+            this.packageProperties.flush();
+        }
+
+        this.flushImpl();
+    }
+
+    /**
+     * Close the open, writable package and save its content.
+     *
+     * If your package is open read only, then you should call {@link #revert()}
+     *  when finished with the package.
+     *
+     * This method is not thread-safe.
+     *
+     * @throws IOException
+     *             If an IO exception occur during the saving process.
+     */
+    @Override
     public void close() throws IOException {
-		if (isClosed()) {
-			return;
-		}
-
-		if (this.packageAccess == PackageAccess.READ) {
-			LOG.atWarn().log("The close() method is intended to SAVE a package. This package is open in READ ONLY mode, use the revert() method instead!");
-			revert();
-			return;
-		}
-		if (this.contentTypeManager == null) {
-		    LOG.atWarn().log("Unable to call close() on a package that hasn't been fully opened yet");
-			revert();
-		    return;
-		}
-
-		if (this.originalPackagePath != null
-				&& !this.originalPackagePath.trim().isEmpty()) {
-			File targetFile = new File(this.originalPackagePath);
-			if (!targetFile.exists()
-					|| !(this.originalPackagePath
-							.equalsIgnoreCase(targetFile.getAbsolutePath()))) {
-				// Case of a package created from scratch
-				save(targetFile);
-			} else {
-				closeImpl();
-			}
-		} else if (this.output != null) {
-			save(this.output);
-			output.close();
-		}
+        if (isClosed()) {
+            return;
+        }
 
-		// ensure all held resources are freed
+        if (this.packageAccess == PackageAccess.READ) {
+            LOG.atWarn().log("The close() method is intended to SAVE a package. This package is open in READ ONLY mode, use the revert() method instead!");
+            revert();
+            return;
+        }
+        if (this.contentTypeManager == null) {
+            LOG.atWarn().log("Unable to call close() on a package that hasn't been fully opened yet");
+            revert();
+            return;
+        }
+
+        if (this.originalPackagePath != null
+                && !this.originalPackagePath.trim().isEmpty()) {
+            File targetFile = new File(this.originalPackagePath);
+            if (!targetFile.exists()
+                    || !(this.originalPackagePath
+                            .equalsIgnoreCase(targetFile.getAbsolutePath()))) {
+                // Case of a package created from scratch
+                save(targetFile);
+            } else {
+                closeImpl();
+            }
+        } else if (this.output != null) {
+            save(this.output);
+            output.close();
+        }
+
+        // ensure all held resources are freed
         revert();
 
-		// Clear
-		this.contentTypeManager.clearAll();
-	}
+        // Clear
+        this.contentTypeManager.clearAll();
+    }
 
     /**
      * Close the package WITHOUT saving its content. Reinitialize this package
@@ -497,9 +497,9 @@ public abstract class OPCPackage impleme
         }
         String name = path.substring(path.lastIndexOf(File.separatorChar) + 1);
 
-		try (FileInputStream is = new FileInputStream(path)) {
-			addThumbnail(name, is);
-		}
+        try (FileInputStream is = new FileInputStream(path)) {
+            addThumbnail(name, is);
+        }
     }
     /**
      * Add a thumbnail to the package. This method is provided to make easier
@@ -566,792 +566,792 @@ public abstract class OPCPackage impleme
         }
     }
 
-	/**
-	 * Throws an exception if the package access mode is in write only mode
-	 * (PackageAccess.Write). This method is call when other methods need write
-	 * right.
-	 *
-	 * @throws InvalidOperationException if a read operation is done on a write only package.
-	 * @see PackageAccess
-	 */
-	void throwExceptionIfWriteOnly() throws InvalidOperationException {
-		if (packageAccess == PackageAccess.WRITE) {
-			throw new InvalidOperationException(
-					"Operation not allowed, document open in write only mode!");
-		}
-	}
-
-	/**
-	 * Retrieves or creates if none exists, core package property part.
-	 *
-	 * @return The PackageProperties part of this package.
-	 */
-	public PackageProperties getPackageProperties()
-			throws InvalidFormatException {
-		this.throwExceptionIfWriteOnly();
-		// If no properties part has been found then we create one
-		if (this.packageProperties == null) {
-			this.packageProperties = new PackagePropertiesPart(this,
-					PackagingURIHelper.CORE_PROPERTIES_PART_NAME);
-		}
-		return this.packageProperties;
-	}
-
-	/**
-	 * Retrieve a part identified by its name.
-	 *
-	 * @param partName
-	 *            Part name of the part to retrieve.
-	 * @return The part with the specified name, else {@code null}.
-	 */
-	public PackagePart getPart(PackagePartName partName) {
-		throwExceptionIfWriteOnly();
-
-		if (partName == null) {
-			throw new IllegalArgumentException("partName");
-		}
-
-		// If the partlist is null, then we parse the package.
-		if (partList == null) {
-			try {
-				getParts();
-			} catch (InvalidFormatException e) {
-				return null;
-			}
-		}
-
-		return partList.get(partName);
-	}
-
-	/**
-	 * Retrieve parts by content type.
-	 *
-	 * @param contentType
-	 *            The content type criteria.
-	 * @return All part associated to the specified content type.
-	 */
-	public ArrayList<PackagePart> getPartsByContentType(String contentType) {
-		ArrayList<PackagePart> retArr = new ArrayList<>();
-		for (PackagePart part : partList.sortedValues()) {
-			if (part.getContentType().equals(contentType)) {
-				retArr.add(part);
-			}
-		}
-		return retArr;
-	}
-
-	/**
-	 * Retrieve parts by relationship type.
-	 *
-	 * @param relationshipType
-	 *            Relationship type. Must not be {@code null}.
-	 * @return All parts which are the target of a relationship with the
-	 *         specified type. If no such parts are found, the list is empty.
-	 * @throws InvalidOperationException If called on a write-only package.
-	 * @throws IllegalArgumentException if relationshipType input param is null.
-	 */
-	public ArrayList<PackagePart> getPartsByRelationshipType(
-			String relationshipType) {
-		if (relationshipType == null) {
-			throw new IllegalArgumentException("relationshipType");
-		}
-		ArrayList<PackagePart> retArr = new ArrayList<>();
-		for (PackageRelationship rel : getRelationshipsByType(relationshipType)) {
-			PackagePart part = getPart(rel);
-			if (part != null) {
-			    retArr.add(part);
-			}
-		}
-		Collections.sort(retArr);
-		return retArr;
-	}
-
-	/**
-	 * Retrieve parts by name
-	 *
-	 * @param namePattern
-	 *            The pattern for matching the names
-	 * @return All parts associated to the specified content type, sorted
-	 * in alphanumerically by the part-name
-	 */
-	public List<PackagePart> getPartsByName(final Pattern namePattern) {
-	    if (namePattern == null) {
-	        throw new IllegalArgumentException("name pattern must not be null");
-	    }
-	    Matcher matcher = namePattern.matcher("");
-	    ArrayList<PackagePart> result = new ArrayList<>();
-	    for (PackagePart part : partList.sortedValues()) {
-	        PackagePartName partName = part.getPartName();
-	        if (matcher.reset(partName.getName()).matches()) {
-	            result.add(part);
-	        }
-	    }
-	    return result;
-	}
-
-	/**
-	 * Get the target part from the specified relationship.
-	 *
-	 * @param partRel
-	 *            The part relationship uses to retrieve the part.
-	 */
-	public PackagePart getPart(PackageRelationship partRel) {
-		PackagePart retPart = null;
-		ensureRelationships();
-		for (PackageRelationship rel : relationships) {
-			if (rel.getRelationshipType().equals(partRel.getRelationshipType())) {
-				try {
-					retPart = getPart(PackagingURIHelper.createPartName(rel
-							.getTargetURI()));
-				} catch (InvalidFormatException e) {
-					continue;
-				}
-				break;
-			}
-		}
-		return retPart;
-	}
-
-	/**
-	 * Load the parts of the archive if it has not been done yet. The
-	 * relationships of each part are not loaded.
-	 *
-	 * Note - Rule M4.1 states that there may only ever be one Core
-	 *  Properties Part, but Office produced files will sometimes
-	 *  have multiple! As Office ignores all but the first, we relax
-	 *  Compliance with Rule M4.1, and ignore all others silently too.
-	 *
-	 * @return All this package's parts.
-	 * @throws InvalidFormatException if the package is not valid.
-	 */
-	public ArrayList<PackagePart> getParts() throws InvalidFormatException {
-		throwExceptionIfWriteOnly();
-
-		// If the part list is null, we parse the package to retrieve all parts.
-		if (partList == null) {
-			/* Variables use to validate OPC Compliance */
-
-			// Check rule M4.1 -> A format consumer shall consider more than
-			// one core properties relationship for a package to be an error
-		    // (We just log it and move on, as real files break this!)
-			boolean hasCorePropertiesPart = false;
-			boolean needCorePropertiesPart = true;
-
-			partList = getPartsImpl();
-			for (PackagePart part : new ArrayList<>(partList.sortedValues())) {
-			    part.loadRelationships();
-
-				// Check OPC compliance rule M4.1
-				if (ContentTypes.CORE_PROPERTIES_PART.equals(part.getContentType())) {
-					if (!hasCorePropertiesPart) {
-						hasCorePropertiesPart = true;
-					} else {
-					   LOG.atWarn().log("OPC Compliance error [M4.1]: " +
-					   		"there is more than one core properties relationship in the package! " +
-					   		"POI will use only the first, but other software may reject this file.");
-					}
-				}
-
-				PartUnmarshaller partUnmarshaller = partUnmarshallers.get(part._contentType);
-
-				if (partUnmarshaller != null) {
-					UnmarshallContext context = new UnmarshallContext(this, part._partName);
-					try {
-						PackagePart unmarshallPart = partUnmarshaller.unmarshall(context, part.getInputStream());
-						partList.remove(part.getPartName());
-						partList.put(unmarshallPart._partName, unmarshallPart);
-
-						// Core properties case-- use first CoreProperties part we come across
-						// and ignore any subsequent ones
-						if (unmarshallPart instanceof PackagePropertiesPart &&
-								hasCorePropertiesPart &&
-								needCorePropertiesPart) {
-							this.packageProperties = (PackagePropertiesPart) unmarshallPart;
-							needCorePropertiesPart = false;
-						}
-					} catch (IOException ioe) {
-						LOG.atWarn().log("Unmarshall operation : IOException for {}", part._partName);
-					} catch (InvalidOperationException invoe) {
-						throw new InvalidFormatException(invoe.getMessage(), invoe);
-					}
-				}
-			}
-		}
-		return new ArrayList<>(partList.sortedValues());
-	}
-
-	/**
-	 * Create and add a part, with the specified name and content type, to the
-	 * package.
-	 *
-	 * @param partName
-	 *            Part name.
-	 * @param contentType
-	 *            Part content type.
-	 * @return The newly created part.
-	 * @throws PartAlreadyExistsException
-	 *             If rule M1.12 is not verified : Packages shall not contain
-	 *             equivalent part names and package implementers shall neither
-	 *             create nor recognize packages with equivalent part names.
-	 * @see #createPartImpl(PackagePartName, String, boolean)
-	 */
-	public PackagePart createPart(PackagePartName partName, String contentType) {
-		return this.createPart(partName, contentType, true);
-	}
-
-	/**
-	 * Create and add a part, with the specified name and content type, to the
-	 * package. For general purpose, prefer the overload version of this method
-	 * without the 'loadRelationships' parameter.
-	 *
-	 * @param partName
-	 *            Part name.
-	 * @param contentType
-	 *            Part content type.
-	 * @param loadRelationships
-	 *            Specify if the existing relationship part, if any, logically
-	 *            associated to the newly created part will be loaded.
-	 * @return The newly created part.
-	 * @throws PartAlreadyExistsException
-	 *             If rule M1.12 is not verified : Packages shall not contain
-	 *             equivalent part names and package implementers shall neither
-	 *             create nor recognize packages with equivalent part names.
-	 * @see #createPartImpl(PackagePartName, String, boolean)
-	 */
-	PackagePart createPart(PackagePartName partName, String contentType,
-			boolean loadRelationships) {
-		throwExceptionIfReadOnly();
-		if (partName == null) {
-			throw new IllegalArgumentException("partName");
-		}
-
-		if (contentType == null || contentType.isEmpty()) {
-			throw new IllegalArgumentException("contentType");
-		}
-
-		// Check if the specified part name already exists
-		if (partList.containsKey(partName)
-				&& !partList.get(partName).isDeleted()) {
-			throw new PartAlreadyExistsException(
-					"A part with the name '" + partName.getName() + "'" +
-					" already exists : Packages shall not contain equivalent part names and package" +
-					" implementers shall neither create nor recognize packages with equivalent part names. [M1.12]");
-		}
-
-		/* Check OPC compliance */
-
-		// Rule [M4.1]: The format designer shall specify and the format producer
-		// shall create at most one core properties relationship for a package.
-		// A format consumer shall consider more than one core properties
-		// relationship for a package to be an error. If present, the
-		// relationship shall target the Core Properties part.
-		// Note - POI will read files with more than one Core Properties, which
-		//  Office sometimes produces, but is strict on generation
-		if (contentType.equals(ContentTypes.CORE_PROPERTIES_PART)) {
-			if (this.packageProperties != null) {
-				throw new InvalidOperationException(
-						"OPC Compliance error [M4.1]: you try to add more than one core properties relationship in the package !");
-			}
-		}
-
-		/* End check OPC compliance */
-
-		PackagePart part = this.createPartImpl(partName, contentType,
-				loadRelationships);
-
-		/* check/create default entries - for bug54803 */
-		try {
-			PackagePartName ppn = PackagingURIHelper.createPartName("/."+EXTENSION_XML);
-			contentTypeManager.addContentType(ppn, PLAIN_OLD_XML);
-			ppn = PackagingURIHelper.createPartName("/"+RELATIONSHIP_PART_EXTENSION_NAME);
-			contentTypeManager.addContentType(ppn, RELATIONSHIPS_PART);
-		} catch (InvalidFormatException e) {
-			throw new InvalidOperationException("unable to create default content-type entries.", e);
-		}
-
-		this.contentTypeManager.addContentType(partName, contentType);
-		this.partList.put(partName, part);
-		this.isDirty = true;
-		return part;
-	}
-
-	/**
-	 * Add a part to the package.
-	 *
-	 * @param partName
-	 *            Part name of the part to create.
-	 * @param contentType
-	 *            type associated with the file
-	 * @param content
-	 *            the contents to add. In order to have faster operation in
-	 *            document merge, the data are stored in memory not on a hard
-	 *            disk
-	 *
-	 * @return The new part.
-	 * @see #createPart(PackagePartName, String)
-	 */
-	public PackagePart createPart(PackagePartName partName, String contentType,
-			ByteArrayOutputStream content) {
-		PackagePart addedPart = this.createPart(partName, contentType);
-		if (addedPart == null) {
-			return null;
-		}
-		// Extract the zip entry content to put it in the part content
-		if (content != null) {
-			try (OutputStream partOutput = addedPart.getOutputStream()) {
-				if (partOutput == null) {
-					return null;
-				}
-				content.writeTo(partOutput);
-			} catch (IOException ignored) {
-				return null;
-			}
-		} else {
-			return null;
-		}
-		return addedPart;
-	}
-
-	/**
-	 * Add the specified part to the package. If a part already exists in the
-	 * package with the same name as the one specified, then we replace the old
-	 * part by the specified part.
-	 *
-	 * @param part
-	 *            The part to add (or replace).
-	 * @return The part added to the package, the same as the one specified.
-	 * @throws InvalidOperationException
-	 *             If rule M1.12 is not verified : Packages shall not contain
-	 *             equivalent part names and package implementers shall neither
-	 *             create nor recognize packages with equivalent part names.
-	 */
-	protected PackagePart addPackagePart(PackagePart part) {
-		throwExceptionIfReadOnly();
-		if (part == null) {
-			throw new IllegalArgumentException("part");
-		}
-
-		if (partList.containsKey(part._partName)) {
-			if (!partList.get(part._partName).isDeleted()) {
-				throw new InvalidOperationException(
-						"A part with the name '"
-								+ part._partName.getName()
-								+ "' already exists : Packages shall not contain equivalent part names and package implementers shall neither create nor recognize packages with equivalent part names. [M1.12]");
-			}
-			// If the specified partis flagged as deleted, we make it
-			// available
-			part.setDeleted(false);
-			// and delete the old part to replace it thereafeter
-			this.partList.remove(part._partName);
-		}
-		this.partList.put(part._partName, part);
-		this.isDirty = true;
-		return part;
-	}
-
-	/**
-	 * Remove the specified part in this package. If this part is relationship
-	 * part, then delete all relationships in the source part.
-	 *
-	 * @param part
-	 *            The part to remove. If {@code null}, skip the action.
-	 * @see #removePart(PackagePartName)
-	 */
-	public void removePart(PackagePart part) {
-		if (part != null) {
-			removePart(part.getPartName());
-		}
-	}
-
-	/**
-	 * Remove a part in this package. If this part is relationship part, then
-	 * delete all relationships in the source part.
-	 *
-	 * @param partName
-	 *            The part name of the part to remove.
-	 */
-	public void removePart(PackagePartName partName) {
-		throwExceptionIfReadOnly();
-		if (partName == null || !this.containPart(partName)) {
-			throw new IllegalArgumentException("partName");
-		}
-
-		// Delete the specified part from the package.
-		if (this.partList.containsKey(partName)) {
-			this.partList.get(partName).setDeleted(true);
-			this.removePartImpl(partName);
-			this.partList.remove(partName);
-		} else {
-			this.removePartImpl(partName);
-		}
-
-		// Delete content type
-		this.contentTypeManager.removeContentType(partName);
-
-		// If this part is a relationship part, then delete all relationships of
-		// the source part.
-		if (partName.isRelationshipPartURI()) {
-			URI sourceURI = PackagingURIHelper
-					.getSourcePartUriFromRelationshipPartUri(partName.getURI());
-			PackagePartName sourcePartName;
-			try {
-				sourcePartName = PackagingURIHelper.createPartName(sourceURI);
-			} catch (InvalidFormatException e) {
-				LOG.atError().log("Part name URI '{}' is not valid! This message is not intended to be displayed!", sourceURI);
-				return;
-			}
-			if (sourcePartName.getURI().equals(
-					PackagingURIHelper.PACKAGE_ROOT_URI)) {
-				clearRelationships();
-			} else if (containPart(sourcePartName)) {
-				PackagePart part = getPart(sourcePartName);
-				if (part != null) {
-					part.clearRelationships();
-				}
-			}
-		}
-
-		this.isDirty = true;
-	}
-
-	/**
-	 * Remove a part from this package as well as its relationship part, if one
-	 * exists, and all parts listed in the relationship part. Be aware that this
-	 * do not delete relationships which target the specified part.
-	 *
-	 * @param partName
-	 *            The name of the part to delete.
-	 * @throws InvalidFormatException
-	 *             Throws if the associated relationship part of the specified
-	 *             part is not valid.
-	 */
-	public void removePartRecursive(PackagePartName partName)
-			throws InvalidFormatException {
-		// Retrieves relationship part, if one exists
-		PackagePart relPart = this.partList.get(PackagingURIHelper
-				.getRelationshipPartName(partName));
-		// Retrieves PackagePart object from the package
-		PackagePart partToRemove = this.partList.get(partName);
-
-		if (relPart != null) {
-			PackageRelationshipCollection partRels = new PackageRelationshipCollection(
-					partToRemove);
-			for (PackageRelationship rel : partRels) {
-				PackagePartName partNameToRemove = PackagingURIHelper
-						.createPartName(PackagingURIHelper.resolvePartUri(rel
-								.getSourceURI(), rel.getTargetURI()));
-				removePart(partNameToRemove);
-			}
-
-			// Finally delete its relationship part if one exists
-			this.removePart(relPart._partName);
-		}
-
-		// Delete the specified part
-		this.removePart(partToRemove._partName);
-	}
-
-	/**
-	 * Delete the part with the specified name and its associated relationships
-	 * part if one exists. Prefer the use of this method to delete a part in the
-	 * package, compare to the remove() methods that don't remove associated
-	 * relationships part.
-	 *
-	 * @param partName
-	 *            Name of the part to delete
-	 */
-	public void deletePart(PackagePartName partName) {
-		if (partName == null) {
-			throw new IllegalArgumentException("partName");
-		}
-
-		// Remove the part
-		this.removePart(partName);
-		// Remove the relationships part
-		this.removePart(PackagingURIHelper.getRelationshipPartName(partName));
-	}
-
-	/**
-	 * Delete the part with the specified name and all part listed in its
-	 * associated relationships part if one exists. This process is recursively
-	 * apply to all parts in the relationships part of the specified part.
-	 * Prefer the use of this method to delete a part in the package, compare to
-	 * the remove() methods that don't remove associated relationships part.
-	 *
-	 * @param partName
-	 *            Name of the part to delete
-	 */
-	public void deletePartRecursive(PackagePartName partName) {
-		if (partName == null || !this.containPart(partName)) {
-			throw new IllegalArgumentException("partName");
-		}
-
-		PackagePart partToDelete = this.getPart(partName);
-		// Remove the part
-		this.removePart(partName);
-		// Remove all relationship parts associated
-		try {
-			for (PackageRelationship relationship : partToDelete
-					.getRelationships()) {
-				PackagePartName targetPartName = PackagingURIHelper
-						.createPartName(PackagingURIHelper.resolvePartUri(
-								partName.getURI(), relationship.getTargetURI()));
-				this.deletePartRecursive(targetPartName);
-			}
-		} catch (InvalidFormatException e) {
-			LOG.atWarn().withThrowable(e).log("An exception occurs while deleting part '{}'. Some parts may remain in the package.", partName.getName());
-			return;
-		}
-		// Remove the relationships part
-		PackagePartName relationshipPartName = PackagingURIHelper
-				.getRelationshipPartName(partName);
-		if (relationshipPartName != null && containPart(relationshipPartName)) {
-			this.removePart(relationshipPartName);
-		}
-	}
-
-	/**
-	 * Check if a part already exists in this package from its name.
-	 *
-	 * @param partName
-	 *            Part name to check.
-	 * @return <i>true</i> if the part is logically added to this package, else
-	 *         <i>false</i>.
-	 */
-	public boolean containPart(PackagePartName partName) {
-		return (this.getPart(partName) != null);
-	}
-
-	/**
-	 * Add a relationship to the package (except relationships part).
-	 *
-	 * Check rule M4.1 : The format designer shall specify and the format
-	 * producer shall create at most one core properties relationship for a
-	 * package. A format consumer shall consider more than one core properties
-	 * relationship for a package to be an error. If present, the relationship
-	 * shall target the Core Properties part.
-	 *
-	 * Check rule M1.25: The Relationships part shall not have relationships to
-	 * any other part. Package implementers shall enforce this requirement upon
-	 * the attempt to create such a relationship and shall treat any such
-	 * relationship as invalid.
-	 *
-	 * @param targetPartName
-	 *            Target part name.
-	 * @param targetMode
-	 *            Target mode, either Internal or External.
-	 * @param relationshipType
-	 *            Relationship type.
-	 * @param relID
-	 *            ID of the relationship.
-	 * @see PackageRelationshipTypes
-	 */
-	@Override
+    /**
+     * Throws an exception if the package access mode is in write only mode
+     * (PackageAccess.Write). This method is call when other methods need write
+     * right.
+     *
+     * @throws InvalidOperationException if a read operation is done on a write only package.
+     * @see PackageAccess
+     */
+    void throwExceptionIfWriteOnly() throws InvalidOperationException {
+        if (packageAccess == PackageAccess.WRITE) {
+            throw new InvalidOperationException(
+                    "Operation not allowed, document open in write only mode!");
+        }
+    }
+
+    /**
+     * Retrieves or creates if none exists, core package property part.
+     *
+     * @return The PackageProperties part of this package.
+     */
+    public PackageProperties getPackageProperties()
+            throws InvalidFormatException {
+        this.throwExceptionIfWriteOnly();
+        // If no properties part has been found then we create one
+        if (this.packageProperties == null) {
+            this.packageProperties = new PackagePropertiesPart(this,
+                    PackagingURIHelper.CORE_PROPERTIES_PART_NAME);
+        }
+        return this.packageProperties;
+    }
+
+    /**
+     * Retrieve a part identified by its name.
+     *
+     * @param partName
+     *            Part name of the part to retrieve.
+     * @return The part with the specified name, else {@code null}.
+     */
+    public PackagePart getPart(PackagePartName partName) {
+        throwExceptionIfWriteOnly();
+
+        if (partName == null) {
+            throw new IllegalArgumentException("partName");
+        }
+
+        // If the partlist is null, then we parse the package.
+        if (partList == null) {
+            try {
+                getParts();
+            } catch (InvalidFormatException e) {
+                return null;
+            }
+        }
+
+        return partList.get(partName);
+    }
+
+    /**
+     * Retrieve parts by content type.
+     *
+     * @param contentType
+     *            The content type criteria.
+     * @return All part associated to the specified content type.
+     */
+    public ArrayList<PackagePart> getPartsByContentType(String contentType) {
+        ArrayList<PackagePart> retArr = new ArrayList<>();
+        for (PackagePart part : partList.sortedValues()) {
+            if (part.getContentType().equals(contentType)) {
+                retArr.add(part);
+            }
+        }
+        return retArr;
+    }
+
+    /**
+     * Retrieve parts by relationship type.
+     *
+     * @param relationshipType
+     *            Relationship type. Must not be {@code null}.
+     * @return All parts which are the target of a relationship with the
+     *         specified type. If no such parts are found, the list is empty.
+     * @throws InvalidOperationException If called on a write-only package.
+     * @throws IllegalArgumentException if relationshipType input param is null.
+     */
+    public ArrayList<PackagePart> getPartsByRelationshipType(
+            String relationshipType) {
+        if (relationshipType == null) {
+            throw new IllegalArgumentException("relationshipType");
+        }
+        ArrayList<PackagePart> retArr = new ArrayList<>();
+        for (PackageRelationship rel : getRelationshipsByType(relationshipType)) {
+            PackagePart part = getPart(rel);
+            if (part != null) {
+                retArr.add(part);
+            }
+        }
+        Collections.sort(retArr);
+        return retArr;
+    }
+
+    /**
+     * Retrieve parts by name
+     *
+     * @param namePattern
+     *            The pattern for matching the names
+     * @return All parts associated to the specified content type, sorted
+     * in alphanumerically by the part-name
+     */
+    public List<PackagePart> getPartsByName(final Pattern namePattern) {
+        if (namePattern == null) {
+            throw new IllegalArgumentException("name pattern must not be null");
+        }
+        Matcher matcher = namePattern.matcher("");
+        ArrayList<PackagePart> result = new ArrayList<>();
+        for (PackagePart part : partList.sortedValues()) {
+            PackagePartName partName = part.getPartName();
+            if (matcher.reset(partName.getName()).matches()) {
+                result.add(part);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Get the target part from the specified relationship.
+     *
+     * @param partRel
+     *            The part relationship uses to retrieve the part.
+     */
+    public PackagePart getPart(PackageRelationship partRel) {
+        PackagePart retPart = null;
+        ensureRelationships();
+        for (PackageRelationship rel : relationships) {
+            if (rel.getRelationshipType().equals(partRel.getRelationshipType())) {
+                try {
+                    retPart = getPart(PackagingURIHelper.createPartName(rel
+                            .getTargetURI()));
+                } catch (InvalidFormatException e) {
+                    continue;
+                }
+                break;
+            }
+        }
+        return retPart;
+    }
+
+    /**
+     * Load the parts of the archive if it has not been done yet. The
+     * relationships of each part are not loaded.
+     *
+     * Note - Rule M4.1 states that there may only ever be one Core
+     *  Properties Part, but Office produced files will sometimes
+     *  have multiple! As Office ignores all but the first, we relax
+     *  Compliance with Rule M4.1, and ignore all others silently too.
+     *
+     * @return All this package's parts.
+     * @throws InvalidFormatException if the package is not valid.
+     */
+    public ArrayList<PackagePart> getParts() throws InvalidFormatException {
+        throwExceptionIfWriteOnly();
+
+        // If the part list is null, we parse the package to retrieve all parts.
+        if (partList == null) {
+            /* Variables use to validate OPC Compliance */
+
+            // Check rule M4.1 -> A format consumer shall consider more than
+            // one core properties relationship for a package to be an error
+            // (We just log it and move on, as real files break this!)
+            boolean hasCorePropertiesPart = false;
+            boolean needCorePropertiesPart = true;
+
+            partList = getPartsImpl();
+            for (PackagePart part : new ArrayList<>(partList.sortedValues())) {
+                part.loadRelationships();
+
+                // Check OPC compliance rule M4.1
+                if (ContentTypes.CORE_PROPERTIES_PART.equals(part.getContentType())) {
+                    if (!hasCorePropertiesPart) {
+                        hasCorePropertiesPart = true;
+                    } else {
+                       LOG.atWarn().log("OPC Compliance error [M4.1]: " +
+                            "there is more than one core properties relationship in the package! " +
+                            "POI will use only the first, but other software may reject this file.");
+                    }
+                }
+
+                PartUnmarshaller partUnmarshaller = partUnmarshallers.get(part._contentType);
+
+                if (partUnmarshaller != null) {
+                    UnmarshallContext context = new UnmarshallContext(this, part._partName);
+                    try {
+                        PackagePart unmarshallPart = partUnmarshaller.unmarshall(context, part.getInputStream());
+                        partList.remove(part.getPartName());
+                        partList.put(unmarshallPart._partName, unmarshallPart);
+
+                        // Core properties case-- use first CoreProperties part we come across
+                        // and ignore any subsequent ones
+                        if (unmarshallPart instanceof PackagePropertiesPart &&
+                                hasCorePropertiesPart &&
+                                needCorePropertiesPart) {
+                            this.packageProperties = (PackagePropertiesPart) unmarshallPart;
+                            needCorePropertiesPart = false;
+                        }
+                    } catch (IOException ioe) {
+                        LOG.atWarn().log("Unmarshall operation : IOException for {}", part._partName);
+                    } catch (InvalidOperationException invoe) {
+                        throw new InvalidFormatException(invoe.getMessage(), invoe);
+                    }
+                }
+            }
+        }
+        return new ArrayList<>(partList.sortedValues());
+    }
+
+    /**
+     * Create and add a part, with the specified name and content type, to the
+     * package.
+     *
+     * @param partName
+     *            Part name.
+     * @param contentType
+     *            Part content type.
+     * @return The newly created part.
+     * @throws PartAlreadyExistsException
+     *             If rule M1.12 is not verified : Packages shall not contain
+     *             equivalent part names and package implementers shall neither
+     *             create nor recognize packages with equivalent part names.
+     * @see #createPartImpl(PackagePartName, String, boolean)
+     */
+    public PackagePart createPart(PackagePartName partName, String contentType) {
+        return this.createPart(partName, contentType, true);
+    }
+
+    /**
+     * Create and add a part, with the specified name and content type, to the
+     * package. For general purpose, prefer the overload version of this method
+     * without the 'loadRelationships' parameter.
+     *
+     * @param partName
+     *            Part name.
+     * @param contentType
+     *            Part content type.
+     * @param loadRelationships
+     *            Specify if the existing relationship part, if any, logically
+     *            associated to the newly created part will be loaded.
+     * @return The newly created part.
+     * @throws PartAlreadyExistsException
+     *             If rule M1.12 is not verified : Packages shall not contain
+     *             equivalent part names and package implementers shall neither
+     *             create nor recognize packages with equivalent part names.
+     * @see #createPartImpl(PackagePartName, String, boolean)
+     */
+    PackagePart createPart(PackagePartName partName, String contentType,
+            boolean loadRelationships) {
+        throwExceptionIfReadOnly();
+        if (partName == null) {
+            throw new IllegalArgumentException("partName");
+        }
+
+        if (contentType == null || contentType.isEmpty()) {
+            throw new IllegalArgumentException("contentType");
+        }
+
+        // Check if the specified part name already exists
+        if (partList.containsKey(partName)
+                && !partList.get(partName).isDeleted()) {
+            throw new PartAlreadyExistsException(
+                    "A part with the name '" + partName.getName() + "'" +
+                    " already exists : Packages shall not contain equivalent part names and package" +
+                    " implementers shall neither create nor recognize packages with equivalent part names. [M1.12]");
+        }
+
+        /* Check OPC compliance */
+
+        // Rule [M4.1]: The format designer shall specify and the format producer
+        // shall create at most one core properties relationship for a package.
+        // A format consumer shall consider more than one core properties
+        // relationship for a package to be an error. If present, the
+        // relationship shall target the Core Properties part.
+        // Note - POI will read files with more than one Core Properties, which
+        //  Office sometimes produces, but is strict on generation
+        if (contentType.equals(ContentTypes.CORE_PROPERTIES_PART)) {
+            if (this.packageProperties != null) {
+                throw new InvalidOperationException(
+                        "OPC Compliance error [M4.1]: you try to add more than one core properties relationship in the package !");
+            }
+        }
+
+        /* End check OPC compliance */
+
+        PackagePart part = this.createPartImpl(partName, contentType,
+                loadRelationships);
+
+        /* check/create default entries - for bug54803 */
+        try {
+            PackagePartName ppn = PackagingURIHelper.createPartName("/."+EXTENSION_XML);
+            contentTypeManager.addContentType(ppn, PLAIN_OLD_XML);
+            ppn = PackagingURIHelper.createPartName("/"+RELATIONSHIP_PART_EXTENSION_NAME);
+            contentTypeManager.addContentType(ppn, RELATIONSHIPS_PART);
+        } catch (InvalidFormatException e) {
+            throw new InvalidOperationException("unable to create default content-type entries.", e);
+        }
+
+        this.contentTypeManager.addContentType(partName, contentType);
+        this.partList.put(partName, part);
+        this.isDirty = true;
+        return part;
+    }
+
+    /**
+     * Add a part to the package.
+     *
+     * @param partName
+     *            Part name of the part to create.
+     * @param contentType
+     *            type associated with the file
+     * @param content
+     *            the contents to add. In order to have faster operation in
+     *            document merge, the data are stored in memory not on a hard
+     *            disk
+     *
+     * @return The new part.
+     * @see #createPart(PackagePartName, String)
+     */
+    public PackagePart createPart(PackagePartName partName, String contentType,
+            ByteArrayOutputStream content) {
+        PackagePart addedPart = this.createPart(partName, contentType);
+        if (addedPart == null) {
+            return null;
+        }
+        // Extract the zip entry content to put it in the part content
+        if (content != null) {
+            try (OutputStream partOutput = addedPart.getOutputStream()) {
+                if (partOutput == null) {
+                    return null;
+                }
+                content.writeTo(partOutput);
+            } catch (IOException ignored) {
+                return null;
+            }
+        } else {
+            return null;
+        }
+        return addedPart;
+    }
+
+    /**
+     * Add the specified part to the package. If a part already exists in the
+     * package with the same name as the one specified, then we replace the old
+     * part by the specified part.
+     *
+     * @param part
+     *            The part to add (or replace).
+     * @return The part added to the package, the same as the one specified.
+     * @throws InvalidOperationException
+     *             If rule M1.12 is not verified : Packages shall not contain
+     *             equivalent part names and package implementers shall neither
+     *             create nor recognize packages with equivalent part names.
+     */
+    protected PackagePart addPackagePart(PackagePart part) {
+        throwExceptionIfReadOnly();
+        if (part == null) {
+            throw new IllegalArgumentException("part");
+        }
+
+        if (partList.containsKey(part._partName)) {
+            if (!partList.get(part._partName).isDeleted()) {
+                throw new InvalidOperationException(
+                        "A part with the name '"
+                                + part._partName.getName()
+                                + "' already exists : Packages shall not contain equivalent part names and package implementers shall neither create nor recognize packages with equivalent part names. [M1.12]");
+            }
+            // If the specified partis flagged as deleted, we make it
+            // available
+            part.setDeleted(false);
+            // and delete the old part to replace it thereafeter
+            this.partList.remove(part._partName);
+        }
+        this.partList.put(part._partName, part);
+        this.isDirty = true;
+        return part;
+    }
+
+    /**
+     * Remove the specified part in this package. If this part is relationship
+     * part, then delete all relationships in the source part.
+     *
+     * @param part
+     *            The part to remove. If {@code null}, skip the action.
+     * @see #removePart(PackagePartName)
+     */
+    public void removePart(PackagePart part) {
+        if (part != null) {
+            removePart(part.getPartName());
+        }
+    }
+
+    /**
+     * Remove a part in this package. If this part is relationship part, then
+     * delete all relationships in the source part.
+     *
+     * @param partName
+     *            The part name of the part to remove.
+     */
+    public void removePart(PackagePartName partName) {
+        throwExceptionIfReadOnly();
+        if (partName == null || !this.containPart(partName)) {
+            throw new IllegalArgumentException("partName");
+        }
+
+        // Delete the specified part from the package.
+        if (this.partList.containsKey(partName)) {
+            this.partList.get(partName).setDeleted(true);
+            this.removePartImpl(partName);
+            this.partList.remove(partName);
+        } else {
+            this.removePartImpl(partName);
+        }
+
+        // Delete content type
+        this.contentTypeManager.removeContentType(partName);
+
+        // If this part is a relationship part, then delete all relationships of
+        // the source part.
+        if (partName.isRelationshipPartURI()) {
+            URI sourceURI = PackagingURIHelper
+                    .getSourcePartUriFromRelationshipPartUri(partName.getURI());
+            PackagePartName sourcePartName;
+            try {
+                sourcePartName = PackagingURIHelper.createPartName(sourceURI);
+            } catch (InvalidFormatException e) {
+                LOG.atError().log("Part name URI '{}' is not valid! This message is not intended to be displayed!", sourceURI);
+                return;
+            }
+            if (sourcePartName.getURI().equals(
+                    PackagingURIHelper.PACKAGE_ROOT_URI)) {
+                clearRelationships();
+            } else if (containPart(sourcePartName)) {
+                PackagePart part = getPart(sourcePartName);
+                if (part != null) {
+                    part.clearRelationships();
+                }
+            }
+        }
+
+        this.isDirty = true;
+    }
+
+    /**
+     * Remove a part from this package as well as its relationship part, if one
+     * exists, and all parts listed in the relationship part. Be aware that this
+     * do not delete relationships which target the specified part.
+     *
+     * @param partName
+     *            The name of the part to delete.
+     * @throws InvalidFormatException
+     *             Throws if the associated relationship part of the specified
+     *             part is not valid.
+     */
+    public void removePartRecursive(PackagePartName partName)
+            throws InvalidFormatException {
+        // Retrieves relationship part, if one exists
+        PackagePart relPart = this.partList.get(PackagingURIHelper
+                .getRelationshipPartName(partName));
+        // Retrieves PackagePart object from the package
+        PackagePart partToRemove = this.partList.get(partName);
+
+        if (relPart != null) {
+            PackageRelationshipCollection partRels = new PackageRelationshipCollection(
+                    partToRemove);
+            for (PackageRelationship rel : partRels) {
+                PackagePartName partNameToRemove = PackagingURIHelper
+                        .createPartName(PackagingURIHelper.resolvePartUri(rel
+                                .getSourceURI(), rel.getTargetURI()));
+                removePart(partNameToRemove);
+            }
+
+            // Finally delete its relationship part if one exists
+            this.removePart(relPart._partName);
+        }
+
+        // Delete the specified part
+        this.removePart(partToRemove._partName);
+    }
+
+    /**
+     * Delete the part with the specified name and its associated relationships
+     * part if one exists. Prefer the use of this method to delete a part in the
+     * package, compare to the remove() methods that don't remove associated
+     * relationships part.
+     *
+     * @param partName
+     *            Name of the part to delete
+     */
+    public void deletePart(PackagePartName partName) {
+        if (partName == null) {
+            throw new IllegalArgumentException("partName");
+        }
+
+        // Remove the part
+        this.removePart(partName);
+        // Remove the relationships part
+        this.removePart(PackagingURIHelper.getRelationshipPartName(partName));
+    }
+
+    /**
+     * Delete the part with the specified name and all part listed in its
+     * associated relationships part if one exists. This process is recursively
+     * apply to all parts in the relationships part of the specified part.
+     * Prefer the use of this method to delete a part in the package, compare to
+     * the remove() methods that don't remove associated relationships part.
+     *
+     * @param partName
+     *            Name of the part to delete
+     */
+    public void deletePartRecursive(PackagePartName partName) {
+        if (partName == null || !this.containPart(partName)) {
+            throw new IllegalArgumentException("partName");
+        }
+
+        PackagePart partToDelete = this.getPart(partName);
+        // Remove the part
+        this.removePart(partName);
+        // Remove all relationship parts associated
+        try {
+            for (PackageRelationship relationship : partToDelete
+                    .getRelationships()) {
+                PackagePartName targetPartName = PackagingURIHelper
+                        .createPartName(PackagingURIHelper.resolvePartUri(
+                                partName.getURI(), relationship.getTargetURI()));
+                this.deletePartRecursive(targetPartName);
+            }
+        } catch (InvalidFormatException e) {
+            LOG.atWarn().withThrowable(e).log("An exception occurs while deleting part '{}'. Some parts may remain in the package.", partName.getName());
+            return;
+        }
+        // Remove the relationships part
+        PackagePartName relationshipPartName = PackagingURIHelper
+                .getRelationshipPartName(partName);
+        if (relationshipPartName != null && containPart(relationshipPartName)) {
+            this.removePart(relationshipPartName);
+        }
+    }
+
+    /**
+     * Check if a part already exists in this package from its name.
+     *
+     * @param partName
+     *            Part name to check.
+     * @return <i>true</i> if the part is logically added to this package, else
+     *         <i>false</i>.
+     */
+    public boolean containPart(PackagePartName partName) {
+        return (this.getPart(partName) != null);
+    }
+
+    /**
+     * Add a relationship to the package (except relationships part).
+     *
+     * Check rule M4.1 : The format designer shall specify and the format
+     * producer shall create at most one core properties relationship for a
+     * package. A format consumer shall consider more than one core properties
+     * relationship for a package to be an error. If present, the relationship
+     * shall target the Core Properties part.
+     *
+     * Check rule M1.25: The Relationships part shall not have relationships to
+     * any other part. Package implementers shall enforce this requirement upon
+     * the attempt to create such a relationship and shall treat any such
+     * relationship as invalid.
+     *
+     * @param targetPartName
+     *            Target part name.
+     * @param targetMode
+     *            Target mode, either Internal or External.
+     * @param relationshipType
+     *            Relationship type.
+     * @param relID
+     *            ID of the relationship.
+     * @see PackageRelationshipTypes
+     */
+    @Override
     public PackageRelationship addRelationship(PackagePartName targetPartName,
-			TargetMode targetMode, String relationshipType, String relID) {
-		/* Check OPC compliance */
+            TargetMode targetMode, String relationshipType, String relID) {
+        /* Check OPC compliance */
 
-		// Check rule M4.1 : The format designer shall specify and the format
-		// producer
-		// shall create at most one core properties relationship for a package.
-		// A format consumer shall consider more than one core properties
-		// relationship for a package to be an error. If present, the
-		// relationship shall target the Core Properties part.
-		if (relationshipType.equals(PackageRelationshipTypes.CORE_PROPERTIES)
-				&& this.packageProperties != null) {
-			throw new InvalidOperationException(
-					"OPC Compliance error [M4.1]: can't add another core properties part ! Use the built-in package method instead.");
-		}
-
-		/*
-		 * Check rule M1.25: The Relationships part shall not have relationships
-		 * to any other part. Package implementers shall enforce this
-		 * requirement upon the attempt to create such a relationship and shall
-		 * treat any such relationship as invalid.
-		 */
-		if (targetPartName.isRelationshipPartURI()) {
-			throw new InvalidOperationException(
-					"Rule M1.25: The Relationships part shall not have relationships to any other part.");
-		}
-
-		/* End OPC compliance */
-
-		ensureRelationships();
-		PackageRelationship retRel = relationships.addRelationship(
-				targetPartName.getURI(), targetMode, relationshipType, relID);
-		this.isDirty = true;
-		return retRel;
-	}
-
-	/**
-	 * Add a package relationship.
-	 *
-	 * @param targetPartName
-	 *            Target part name.
-	 * @param targetMode
-	 *            Target mode, either Internal or External.
-	 * @param relationshipType
-	 *            Relationship type.
-	 * @see PackageRelationshipTypes
-	 */
-	@Override
+        // Check rule M4.1 : The format designer shall specify and the format
+        // producer
+        // shall create at most one core properties relationship for a package.
+        // A format consumer shall consider more than one core properties
+        // relationship for a package to be an error. If present, the
+        // relationship shall target the Core Properties part.
+        if (relationshipType.equals(PackageRelationshipTypes.CORE_PROPERTIES)
+                && this.packageProperties != null) {
+            throw new InvalidOperationException(
+                    "OPC Compliance error [M4.1]: can't add another core properties part ! Use the built-in package method instead.");
+        }
+
+        /*
+         * Check rule M1.25: The Relationships part shall not have relationships
+         * to any other part. Package implementers shall enforce this
+         * requirement upon the attempt to create such a relationship and shall
+         * treat any such relationship as invalid.
+         */
+        if (targetPartName.isRelationshipPartURI()) {
+            throw new InvalidOperationException(
+                    "Rule M1.25: The Relationships part shall not have relationships to any other part.");
+        }
+
+        /* End OPC compliance */
+
+        ensureRelationships();
+        PackageRelationship retRel = relationships.addRelationship(
+                targetPartName.getURI(), targetMode, relationshipType, relID);
+        this.isDirty = true;
+        return retRel;
+    }
+
+    /**
+     * Add a package relationship.
+     *
+     * @param targetPartName
+     *            Target part name.
+     * @param targetMode
+     *            Target mode, either Internal or External.
+     * @param relationshipType
+     *            Relationship type.
+     * @see PackageRelationshipTypes
+     */
+    @Override
     public PackageRelationship addRelationship(PackagePartName targetPartName,
-			TargetMode targetMode, String relationshipType) {
-		return this.addRelationship(targetPartName, targetMode,
-				relationshipType, null);
-	}
-
-	/**
-	 * Adds an external relationship to a part (except relationships part).
-	 *
-	 * The targets of external relationships are not subject to the same
-	 * validity checks that internal ones are, as the contents is potentially
-	 * any file, URL or similar.
-	 *
-	 * @param target
-	 *            External target of the relationship
-	 * @param relationshipType
-	 *            Type of relationship.
-	 * @return The newly created and added relationship
-	 */
-	@Override
+            TargetMode targetMode, String relationshipType) {
+        return this.addRelationship(targetPartName, targetMode,
+                relationshipType, null);
+    }
+
+    /**
+     * Adds an external relationship to a part (except relationships part).
+     *
+     * The targets of external relationships are not subject to the same
+     * validity checks that internal ones are, as the contents is potentially
+     * any file, URL or similar.
+     *
+     * @param target
+     *            External target of the relationship
+     * @param relationshipType
+     *            Type of relationship.
+     * @return The newly created and added relationship
+     */
+    @Override
     public PackageRelationship addExternalRelationship(String target,
-			String relationshipType) {
-		return addExternalRelationship(target, relationshipType, null);
-	}
-
-	/**
-	 * Adds an external relationship to a part (except relationships part).
-	 *
-	 * The targets of external relationships are not subject to the same
-	 * validity checks that internal ones are, as the contents is potentially
-	 * any file, URL or similar.
-	 *
-	 * @param target
-	 *            External target of the relationship
-	 * @param relationshipType
-	 *            Type of relationship.
-	 * @param id
-	 *            Relationship unique id.
-	 * @return The newly created and added relationship
-	 * @see RelationshipSource#addExternalRelationship(String,
-	 *      String)
-	 */
-	@Override
+            String relationshipType) {
+        return addExternalRelationship(target, relationshipType, null);
+    }
+
+    /**
+     * Adds an external relationship to a part (except relationships part).
+     *
+     * The targets of external relationships are not subject to the same
+     * validity checks that internal ones are, as the contents is potentially
+     * any file, URL or similar.
+     *
+     * @param target
+     *            External target of the relationship
+     * @param relationshipType
+     *            Type of relationship.
+     * @param id
+     *            Relationship unique id.
+     * @return The newly created and added relationship
+     * @see RelationshipSource#addExternalRelationship(String,
+     *      String)
+     */
+    @Override
     public PackageRelationship addExternalRelationship(String target,
-			String relationshipType, String id) {
-		if (target == null) {
-			throw new IllegalArgumentException("target");
-		}
-		if (relationshipType == null) {
-			throw new IllegalArgumentException("relationshipType");
-		}
-
-		URI targetURI;
-		try {
-			targetURI = new URI(target);
-		} catch (URISyntaxException e) {
-			throw new IllegalArgumentException("Invalid target - " + e);
-		}
-
-		ensureRelationships();
-		PackageRelationship retRel = relationships.addRelationship(targetURI,
-				TargetMode.EXTERNAL, relationshipType, id);
-		this.isDirty = true;
-		return retRel;
-	}
-
-	/**
-	 * Delete a relationship from this package.
-	 *
-	 * @param id
-	 *            Id of the relationship to delete.
-	 */
-	@Override
+            String relationshipType, String id) {
+        if (target == null) {
+            throw new IllegalArgumentException("target");
+        }
+        if (relationshipType == null) {
+            throw new IllegalArgumentException("relationshipType");
+        }
+
+        URI targetURI;
+        try {
+            targetURI = new URI(target);
+        } catch (URISyntaxException e) {
+            throw new IllegalArgumentException("Invalid target - " + e);
+        }
+
+        ensureRelationships();
+        PackageRelationship retRel = relationships.addRelationship(targetURI,
+                TargetMode.EXTERNAL, relationshipType, id);
+        this.isDirty = true;
+        return retRel;
+    }
+
+    /**
+     * Delete a relationship from this package.
+     *
+     * @param id
+     *            Id of the relationship to delete.
+     */
+    @Override
     public void removeRelationship(String id) {
-		if (relationships != null) {
-			relationships.removeRelationship(id);
-			this.isDirty = true;
-		}
-	}
-
-	/**
-	 * Retrieves all package relationships.
-	 *
-	 * @return All package relationships of this package.
+        if (relationships != null) {
+            relationships.removeRelationship(id);
+            this.isDirty = true;
+        }
+    }
+
+    /**
+     * Retrieves all package relationships.
+     *
+     * @return All package relationships of this package.
      * @throws InvalidOperationException if a read operation is done on a write only package.
-	 * @see #getRelationshipsHelper(String)
-	 */
-	@Override
+     * @see #getRelationshipsHelper(String)
+     */
+    @Override
     public PackageRelationshipCollection getRelationships() {
-		return getRelationshipsHelper(null);
-	}
+        return getRelationshipsHelper(null);
+    }
 
-	/**
-	 * Retrieves all relationships with the specified type.
-	 *
-	 * @param relationshipType
-	 *            The filter specifying the relationship type.
-	 * @return All relationships with the specified relationship type.
-	 */
-	@Override
+    /**
+     * Retrieves all relationships with the specified type.
+     *
+     * @param relationshipType
+     *            The filter specifying the relationship type.
+     * @return All relationships with the specified relationship type.
+     */
+    @Override
     public PackageRelationshipCollection getRelationshipsByType(
-			String relationshipType) {
-		throwExceptionIfWriteOnly();
-		if (relationshipType == null) {
-			throw new IllegalArgumentException("relationshipType");
-		}
-		return getRelationshipsHelper(relationshipType);
-	}
-
-	/**
-	 * Retrieves all relationships with specified id (normally just ine because
-	 * a relationship id is supposed to be unique).
-	 *
-	 * @param id
-	 *            Id of the wanted relationship.
-	 */
-	private PackageRelationshipCollection getRelationshipsHelper(String id) {
-		throwExceptionIfWriteOnly();
-		ensureRelationships();
-		return this.relationships.getRelationships(id);
-	}
-
-	/**
-	 * Clear package relationships.
-	 */
-	@Override
+            String relationshipType) {
+        throwExceptionIfWriteOnly();
+        if (relationshipType == null) {
+            throw new IllegalArgumentException("relationshipType");
+        }
+        return getRelationshipsHelper(relationshipType);
+    }
+
+    /**
+     * Retrieves all relationships with specified id (normally just ine because
+     * a relationship id is supposed to be unique).
+     *
+     * @param id
+     *            Id of the wanted relationship.
+     */
+    private PackageRelationshipCollection getRelationshipsHelper(String id) {
+        throwExceptionIfWriteOnly();
+        ensureRelationships();
+        return this.relationships.getRelationships(id);
+    }
+
+    /**
+     * Clear package relationships.
+     */
+    @Override
     public void clearRelationships() {
-		if (relationships != null) {
-			relationships.clear();
-			this.isDirty = true;
-		}
-	}
-
-	/**
-	 * Ensure that the relationships collection is not null.
-	 */
-	public void ensureRelationships() {
-		if (this.relationships == null) {
-			try {
-				this.relationships = new PackageRelationshipCollection(this);
-			} catch (InvalidFormatException e) {
-				this.relationships = new PackageRelationshipCollection();
-			}
-		}
-	}
+        if (relationships != null) {
+            relationships.clear();
+            this.isDirty = true;
+        }
+    }
 
-	@Override
+    /**
+     * Ensure that the relationships collection is not null.
+     */
+    public void ensureRelationships() {
+        if (this.relationships == null) {
+            try {
+                this.relationships = new PackageRelationshipCollection(this);
+            } catch (InvalidFormatException e) {
+                this.relationships = new PackageRelationshipCollection();
+            }
+        }
+    }
+
+    @Override
     public PackageRelationship getRelationship(String id) {
-		return this.relationships.getRelationshipByID(id);
-	}
+        return this.relationships.getRelationshipByID(id);
+    }
 
-	@Override
+    @Override
     public boolean hasRelationships() {
-		return (relationships.size() > 0);
-	}
+        return (relationships.size() > 0);
+    }
 
-	@Override
+    @Override
     public boolean isRelationshipExists(PackageRelationship rel) {
         for (PackageRelationship r : relationships) {
             if (r == rel) {
@@ -1359,201 +1359,201 @@ public abstract class OPCPackage impleme
             }
         }
         return false;
-	}
+    }
+
+    /**
+     * Add a marshaller.
+     *
+     * @param contentType
+     *            The content type to bind to the specified marshaller.
+     * @param marshaller
+     *            The marshaller to register with the specified content type.
+     */
+    public void addMarshaller(String contentType, PartMarshaller marshaller) {
+        try {
+            partMarshallers.put(new ContentType(contentType), marshaller);
+        } catch (InvalidFormatException e) {
+            LOG.atWarn().log("The specified content type is not valid: '{}'. The marshaller will not be added !", e.getMessage());
+        }
+    }
+
+    /**
+     * Add an unmarshaller.
+     *
+     * @param contentType
+     *            The content type to bind to the specified unmarshaller.
+     * @param unmarshaller
+     *            The unmarshaller to register with the specified content type.
+     */
+    public void addUnmarshaller(String contentType,
+            PartUnmarshaller unmarshaller) {
+        try {
+            partUnmarshallers.put(new ContentType(contentType), unmarshaller);
+        } catch (InvalidFormatException e) {
+            LOG.atWarn().log("The specified content type is not valid: '{}'. The unmarshaller will not be added !", e.getMessage());
+        }
+    }
 
-	/**
-	 * Add a marshaller.
-	 *
-	 * @param contentType
-	 *            The content type to bind to the specified marshaller.
-	 * @param marshaller
-	 *            The marshaller to register with the specified content type.
-	 */
-	public void addMarshaller(String contentType, PartMarshaller marshaller) {
-		try {
-			partMarshallers.put(new ContentType(contentType), marshaller);
-		} catch (InvalidFormatException e) {
-			LOG.atWarn().log("The specified content type is not valid: '{}'. The marshaller will not be added !", e.getMessage());
-		}
-	}
-
-	/**
-	 * Add an unmarshaller.
-	 *
-	 * @param contentType
-	 *            The content type to bind to the specified unmarshaller.
-	 * @param unmarshaller
-	 *            The unmarshaller to register with the specified content type.
-	 */
-	public void addUnmarshaller(String contentType,
-			PartUnmarshaller unmarshaller) {
-		try {
-			partUnmarshallers.put(new ContentType(contentType), unmarshaller);
-		} catch (InvalidFormatException e) {
-			LOG.atWarn().log("The specified content type is not valid: '{}'. The unmarshaller will not be added !", e.getMessage());
-		}
-	}
-
-	/**
-	 * Remove a marshaller by its content type.
-	 *
-	 * @param contentType
-	 *            The content type associated with the marshaller to remove.
-	 */
-	public void removeMarshaller(String contentType) {
-		try {
+    /**
+     * Remove a marshaller by its content type.
+     *
+     * @param contentType
+     *            The content type associated with the marshaller to remove.
+     */
+    public void removeMarshaller(String contentType) {
+        try {
             partMarshallers.remove(new ContentType(contentType));
         } catch (InvalidFormatException e) {
             throw new RuntimeException(e);
         }
-	}
+    }
 
-	/**
-	 * Remove an unmarshaller by its content type.
-	 *
-	 * @param contentType
-	 *            The content type associated with the unmarshaller to remove.
-	 */
-	public void removeUnmarshaller(String contentType) {
+    /**
+     * Remove an unmarshaller by its content type.
+     *
+     * @param contentType
+     *            The content type associated with the unmarshaller to remove.
+     */
+    public void removeUnmarshaller(String contentType) {
         try {
             partUnmarshallers.remove(new ContentType(contentType));
         } catch (InvalidFormatException e) {
             throw new RuntimeException(e);
         }
-	}
+    }
+
+
+    /* Accesseurs */
+
+    /**
+     * Get the package access mode.
+     *
+     * @return the packageAccess The current package access.
+     */
+    public PackageAccess getPackageAccess() {
+        return packageAccess;
+    }
+
+    /**
+     * Validates the package compliance with the OPC specifications.
+     *
+     * @return <b>true</b> if the package is valid else <b>false</b>
+     */
+    @NotImplemented
+    public boolean validatePackage(OPCPackage pkg) throws InvalidFormatException {
+        throw new InvalidOperationException("Not implemented yet !!!");
+    }
+
+    /**
+     * Save the document in the specified file.
+     *
+     * @param targetFile
+     *            Destination file.
+     * @throws IOException
+     *             Throws if an IO exception occur.
+     * @see #save(OutputStream)
+     */
+    public void save(File targetFile) throws IOException {
+        if (targetFile == null) {
+            throw new IllegalArgumentException("targetFile");
+        }
 
+        this.throwExceptionIfReadOnly();
 
-	/* Accesseurs */
+        // You shouldn't save the the same file, do a close instead
+        if(targetFile.exists() &&
+                targetFile.getAbsolutePath().equals(this.originalPackagePath)) {
+            throw new InvalidOperationException(
+                    "You can't call save(File) to save to the currently open " +
+                    "file. To save to the current file, please just call close()"
+            );
+        }
 
-	/**
-	 * Get the package access mode.
-	 *
-	 * @return the packageAccess The current package access.
-	 */
-	public PackageAccess getPackageAccess() {
-		return packageAccess;
-	}
-
-	/**
-	 * Validates the package compliance with the OPC specifications.
-	 *
-	 * @return <b>true</b> if the package is valid else <b>false</b>
-	 */
-	@NotImplemented
-	public boolean validatePackage(OPCPackage pkg) throws InvalidFormatException {
-		throw new InvalidOperationException("Not implemented yet !!!");
-	}
-
-	/**
-	 * Save the document in the specified file.
-	 *
-	 * @param targetFile
-	 *            Destination file.
-	 * @throws IOException
-	 *             Throws if an IO exception occur.
-	 * @see #save(OutputStream)
-	 */
-	public void save(File targetFile) throws IOException {
-		if (targetFile == null) {
-			throw new IllegalArgumentException("targetFile");
-		}
-
-		this.throwExceptionIfReadOnly();
-
-		// You shouldn't save the the same file, do a close instead
-		if(targetFile.exists() &&
-		        targetFile.getAbsolutePath().equals(this.originalPackagePath)) {
-		    throw new InvalidOperationException(
-		            "You can't call save(File) to save to the currently open " +
-		            "file. To save to the current file, please just call close()"
-		    );
-		}
-
-		// Do the save
-		try (FileOutputStream fos = new FileOutputStream(targetFile)) {
-			this.save(fos);
-		}
-	}
-
-	/**
-	 * Save the document in the specified output stream.
-	 *
-	 * @param outputStream
-	 *            The stream to save the package.
-	 * @see #saveImpl(OutputStream)
-	 */
-	public void save(OutputStream outputStream) throws IOException {
-		throwExceptionIfReadOnly();
-		this.saveImpl(outputStream);
-	}
-
-	/**
-	 * Core method to create a package part. This method must be implemented by
-	 * the subclass.
-	 *
-	 * @param partName
-	 *            URI of the part to create.
-	 * @param contentType
-	 *            Content type of the part to create.
-	 * @return The newly created package part.
-	 */
-	protected abstract PackagePart createPartImpl(PackagePartName partName,
-			String contentType, boolean loadRelationships);
-
-	/**
-	 * Core method to delete a package part. This method must be implemented by
-	 * the subclass.
-	 *
-	 * @param partName
-	 *            The URI of the part to delete.
-	 */
-	protected abstract void removePartImpl(PackagePartName partName);
-
-	/**
-	 * Flush the package but not save.
-	 */
-	protected abstract void flushImpl();
-
-	/**
-	 * Close the package and cause a save of the package.
-	 *
-	 */
-	protected abstract void closeImpl() throws IOException;
-
-	/**
-	 * Close the package without saving the document. Discard all changes made
-	 * to this package.
-	 */
-	protected abstract void revertImpl();
-
-	/**
-	 * Save the package into the specified output stream.
-	 *
-	 * @param outputStream
-	 *            The output stream use to save this package.
-	 */
-	protected abstract void saveImpl(OutputStream outputStream)
-			throws IOException;
-
-	/**
-	 * Get all parts link to the package.
-	 *
-	 * @return A list of the part owned by the package.
-	 */
-	protected abstract PackagePartCollection getPartsImpl()
-			throws InvalidFormatException;
+        // Do the save
+        try (FileOutputStream fos = new FileOutputStream(targetFile)) {
+            this.save(fos);
+        }
+    }
+
+    /**
+     * Save the document in the specified output stream.
+     *
+     * @param outputStream
+     *            The stream to save the package.
+     * @see #saveImpl(OutputStream)
+     */
+    public void save(OutputStream outputStream) throws IOException {
+        throwExceptionIfReadOnly();
+        this.saveImpl(outputStream);
+    }
+
+    /**
+     * Core method to create a package part. This method must be implemented by
+     * the subclass.
+     *
+     * @param partName
+     *            URI of the part to create.
+     * @param contentType
+     *            Content type of the part to create.
+     * @return The newly created package part.
+     */
+    protected abstract PackagePart createPartImpl(PackagePartName partName,
+            String contentType, boolean loadRelationships);
+
+    /**
+     * Core method to delete a package part. This method must be implemented by
+     * the subclass.
+     *
+     * @param partName
+     *            The URI of the part to delete.
+     */

[... 107 lines stripped ...]


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org