You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ye...@apache.org on 2009/01/29 13:44:35 UTC

svn commit: r738842 [3/7] - in /poi/trunk: ./ legal/ maven/ src/documentation/content/xdocs/ src/documentation/content/xdocs/oxml4j/ src/documentation/content/xdocs/spreadsheet/ src/examples/src/org/apache/poi/xssf/eventusermodel/examples/ src/ooxml/ja...

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartName.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartName.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartName.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartName.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,509 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
+
+/**
+ * An immutable Open Packaging Convention compliant part name.
+ * 
+ * @author Julien Chable
+ * @version 0.1
+ * 
+ * @see http://www.ietf.org/rfc/rfc3986.txt
+ */
+public final class PackagePartName implements Comparable<PackagePartName> {
+
+	/**
+	 * Part name stored as an URI.
+	 */
+	private URI partNameURI;
+
+	/*
+	 * URI Characters definition (RFC 3986)
+	 */
+
+	/**
+	 * Reserved characters for sub delimitations.
+	 */
+	private static String[] RFC3986_PCHAR_SUB_DELIMS = { "!", "$", "&", "'",
+			"(", ")", "*", "+", ",", ";", "=" };
+
+	/**
+	 * Unreserved character (+ ALPHA & DIGIT).
+	 */
+	private static String[] RFC3986_PCHAR_UNRESERVED_SUP = { "-", ".", "_", "~" };
+
+	/**
+	 * Authorized reserved characters for pChar.
+	 */
+	private static String[] RFC3986_PCHAR_AUTHORIZED_SUP = { ":", "@" };
+
+	/**
+	 * Flag to know if this part name is from a relationship part name.
+	 */
+	private boolean isRelationship;
+
+	/**
+	 * Constructor. Makes a ValidPartName object from a java.net.URI
+	 * 
+	 * @param uri
+	 *            The URI to validate and to transform into ValidPartName.
+	 * @param checkConformance
+	 *            Flag to specify if the contructor have to validate the OPC
+	 *            conformance. Must be always <code>true</code> except for
+	 *            special URI like '/' which is needed for internal use by
+	 *            OpenXML4J but is not valid.
+	 * @throws InvalidFormatException
+	 *             Throw if the specified part name is not conform to Open
+	 *             Packaging Convention specifications.
+	 * @see java.net.URI
+	 */
+	PackagePartName(URI uri, boolean checkConformance)
+			throws InvalidFormatException {
+		if (checkConformance) {
+			throwExceptionIfInvalidPartUri(uri);
+		} else {
+			if (!PackagingURIHelper.PACKAGE_ROOT_URI.equals(uri)) {
+				throw new OpenXML4JRuntimeException(
+						"OCP conformance must be check for ALL part name except special cases : ['/']");
+			}
+		}
+		this.partNameURI = uri;
+		this.isRelationship = isRelationshipPartURI(this.partNameURI);
+	}
+
+	/**
+	 * Constructor. Makes a ValidPartName object from a String part name.
+	 * 
+	 * @param partName
+	 *            Part name to valid and to create.
+	 * @param checkConformance
+	 *            Flag to specify if the contructor have to validate the OPC
+	 *            conformance. Must be always <code>true</code> except for
+	 *            special URI like '/' which is needed for internal use by
+	 *            OpenXML4J but is not valid.
+	 * @throws InvalidFormatException
+	 *             Throw if the specified part name is not conform to Open
+	 *             Packaging Convention specifications.
+	 */
+	PackagePartName(String partName, boolean checkConformance)
+			throws InvalidFormatException {
+		URI partURI;
+		try {
+			partURI = new URI(partName);
+		} catch (URISyntaxException e) {
+			throw new IllegalArgumentException(
+					"partName argmument is not a valid OPC part name !");
+		}
+
+		if (checkConformance) {
+			throwExceptionIfInvalidPartUri(partURI);
+		} else {
+			if (!PackagingURIHelper.PACKAGE_ROOT_URI.equals(partURI)) {
+				throw new OpenXML4JRuntimeException(
+						"OCP conformance must be check for ALL part name except special cases : ['/']");
+			}
+		}
+		this.partNameURI = partURI;
+		this.isRelationship = isRelationshipPartURI(this.partNameURI);
+	}
+
+	/**
+	 * Check if the specified part name is a relationship part name.
+	 * 
+	 * @param partUri
+	 *            The URI to check.
+	 * @return <code>true</code> if this part name respect the relationship
+	 *         part naming convention else <code>false</code>.
+	 */
+	private boolean isRelationshipPartURI(URI partUri) {
+		if (partUri == null)
+			throw new IllegalArgumentException("partUri");
+
+		return partUri.getPath().matches(
+				"^.*/" + PackagingURIHelper.RELATIONSHIP_PART_SEGMENT_NAME + "/.*\\"
+						+ PackagingURIHelper.RELATIONSHIP_PART_EXTENSION_NAME
+						+ "$");
+	}
+
+	/**
+	 * Know if this part name is a relationship part name.
+	 * 
+	 * @return <code>true</code> if this part name respect the relationship
+	 *         part naming convention else <code>false</code>.
+	 */
+	public boolean isRelationshipPartURI() {
+		return this.isRelationship;
+	}
+
+	/**
+	 * Throws an exception (of any kind) if the specified part name does not
+	 * follow the Open Packaging Convention specifications naming rules.
+	 * 
+	 * @param partUri
+	 *            The part name to check.
+	 * @throws Exception
+	 *             Throws if the part name is invalid.
+	 */
+	private static void throwExceptionIfInvalidPartUri(URI partUri)
+			throws InvalidFormatException {
+		if (partUri == null)
+			throw new IllegalArgumentException("partUri");
+		// Check if the part name URI is empty [M1.1]
+		throwExceptionIfEmptyURI(partUri);
+
+		// Check if the part name URI is absolute
+		throwExceptionIfAbsoluteUri(partUri);
+
+		// Check if the part name URI starts with a forward slash [M1.4]
+		throwExceptionIfPartNameNotStartsWithForwardSlashChar(partUri);
+
+		// Check if the part name URI ends with a forward slash [M1.5]
+		throwExceptionIfPartNameEndsWithForwardSlashChar(partUri);
+
+		// Check if the part name does not have empty segments. [M1.3]
+		// Check if a segment ends with a dot ('.') character. [M1.9]
+		throwExceptionIfPartNameHaveInvalidSegments(partUri);
+	}
+
+	/**
+	 * Throws an exception if the specified URI is empty. [M1.1]
+	 * 
+	 * @param partURI
+	 *            Part URI to check.
+	 * @throws InvalidFormatException
+	 *             If the specified URI is empty.
+	 */
+	private static void throwExceptionIfEmptyURI(URI partURI)
+			throws InvalidFormatException {
+		if (partURI == null)
+			throw new IllegalArgumentException("partURI");
+
+		String uriPath = partURI.getPath();
+		if (uriPath.length() == 0
+				|| ((uriPath.length() == 1) && (uriPath.charAt(0) == PackagingURIHelper.FORWARD_SLASH_CHAR)))
+			throw new InvalidFormatException(
+					"A part name shall not be empty [M1.1]: "
+							+ partURI.getPath());
+	}
+
+	/**
+	 * Throws an exception if the part name has empty segments. [M1.3]
+	 * 
+	 * Throws an exception if a segment any characters other than pchar
+	 * characters. [M1.6]
+	 * 
+	 * Throws an exception if a segment contain percent-encoded forward slash
+	 * ('/'), or backward slash ('\') characters. [M1.7]
+	 * 
+	 * Throws an exception if a segment contain percent-encoded unreserved
+	 * characters. [M1.8]
+	 * 
+	 * Throws an exception if the specified part name's segments end with a dot
+	 * ('.') character. [M1.9]
+	 * 
+	 * Throws an exception if a segment doesn't include at least one non-dot
+	 * character. [M1.10]
+	 * 
+	 * @param partUri
+	 *            The part name to check.
+	 * @throws InvalidFormatException
+	 *             if the specified URI contain an empty segments or if one the
+	 *             segments contained in the part name, ends with a dot ('.')
+	 *             character.
+	 */
+	private static void throwExceptionIfPartNameHaveInvalidSegments(URI partUri)
+			throws InvalidFormatException {
+		if (partUri == null || "".equals(partUri)) {
+			throw new IllegalArgumentException("partUri");
+		}
+
+		// Split the URI into several part and analyze each
+		String[] segments = partUri.toASCIIString().split("/");
+		if (segments.length <= 1 || !segments[0].equals(""))
+			throw new InvalidFormatException(
+					"A part name shall not have empty segments [M1.3]: "
+							+ partUri.getPath());
+
+		for (int i = 1; i < segments.length; ++i) {
+			String seg = segments[i];
+			if (seg == null || "".equals(seg)) {
+				throw new InvalidFormatException(
+						"A part name shall not have empty segments [M1.3]: "
+								+ partUri.getPath());
+			}
+
+			if (seg.endsWith(".")) {
+				throw new InvalidFormatException(
+						"A segment shall not end with a dot ('.') character [M1.9]: "
+								+ partUri.getPath());
+			}
+
+			if ("".equals(seg.replaceAll("\\\\.", ""))) {
+				// Normally will never been invoked with the previous
+				// implementation rule [M1.9]
+				throw new InvalidFormatException(
+						"A segment shall include at least one non-dot character. [M1.10]: "
+								+ partUri.getPath());
+			}
+
+			/*
+			 * Check for rule M1.6, M1.7, M1.8
+			 */
+			checkPCharCompliance(seg);
+		}
+	}
+
+	/**
+	 * Throws an exception if a segment any characters other than pchar
+	 * characters. [M1.6]
+	 * 
+	 * Throws an exception if a segment contain percent-encoded forward slash
+	 * ('/'), or backward slash ('\') characters. [M1.7]
+	 * 
+	 * Throws an exception if a segment contain percent-encoded unreserved
+	 * characters. [M1.8]
+	 * 
+	 * @param segment
+	 *            The segment to check
+	 */
+	private static void checkPCharCompliance(String segment)
+			throws InvalidFormatException {
+		boolean errorFlag;
+		for (int i = 0; i < segment.length(); ++i) {
+			char c = segment.charAt(i);
+			errorFlag = true;
+
+			/* Check rule M1.6 */
+
+			// Check for digit or letter
+			if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
+					|| (c >= '0' && c <= '9')) {
+				errorFlag = false;
+			} else {
+				// Check "-", ".", "_", "~"
+				for (int j = 0; j < RFC3986_PCHAR_UNRESERVED_SUP.length; ++j) {
+					if (c == RFC3986_PCHAR_UNRESERVED_SUP[j].charAt(0)) {
+						errorFlag = false;
+						break;
+					}
+				}
+
+				// Check ":", "@"
+				for (int j = 0; errorFlag
+						&& j < RFC3986_PCHAR_AUTHORIZED_SUP.length; ++j) {
+					if (c == RFC3986_PCHAR_AUTHORIZED_SUP[j].charAt(0)) {
+						errorFlag = false;
+					}
+				}
+
+				// Check "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
+				for (int j = 0; errorFlag
+						&& j < RFC3986_PCHAR_SUB_DELIMS.length; ++j) {
+					if (c == RFC3986_PCHAR_SUB_DELIMS[j].charAt(0)) {
+						errorFlag = false;
+					}
+				}
+			}
+
+			if (errorFlag && c == '%') {
+				// We certainly found an encoded character, check for length
+				// now ( '%' HEXDIGIT HEXDIGIT)
+				if (((segment.length() - i) < 2)) {
+					throw new InvalidFormatException("The segment " + segment
+							+ " contain invalid encoded character !");
+				}
+
+				// If not percent encoded character error occur then reset the
+				// flag -> the character is valid
+				errorFlag = false;
+
+				// Decode the encoded character
+				char decodedChar = (char) Integer.parseInt(segment.substring(
+						i + 1, i + 3), 16);
+				i += 2;
+
+				/* Check rule M1.7 */
+				if (decodedChar == '/' || decodedChar == '\\')
+					throw new InvalidFormatException(
+							"A segment shall not contain percent-encoded forward slash ('/'), or backward slash ('\') characters. [M1.7]");
+
+				/* Check rule M1.8 */
+
+				// Check for unreserved character like define in RFC3986
+				if ((decodedChar >= 'A' && decodedChar <= 'Z')
+						|| (decodedChar >= 'a' && decodedChar <= 'z')
+						|| (decodedChar >= '0' && decodedChar <= '9'))
+					errorFlag = true;
+
+				// Check for unreserved character "-", ".", "_", "~"
+				for (int j = 0; !errorFlag
+						&& j < RFC3986_PCHAR_UNRESERVED_SUP.length; ++j) {
+					if (c == RFC3986_PCHAR_UNRESERVED_SUP[j].charAt(0)) {
+						errorFlag = true;
+						break;
+					}
+				}
+				if (errorFlag)
+					throw new InvalidFormatException(
+							"A segment shall not contain percent-encoded unreserved characters. [M1.8]");
+			}
+
+			if (errorFlag)
+				throw new InvalidFormatException(
+						"A segment shall not hold any characters other than pchar characters. [M1.6]");
+		}
+	}
+
+	/**
+	 * Throws an exception if the specified part name doesn't start with a
+	 * forward slash character '/'. [M1.4]
+	 * 
+	 * @param partUri
+	 *            The part name to check.
+	 * @throws InvalidFormatException
+	 *             If the specified part name doesn't start with a forward slash
+	 *             character '/'.
+	 */
+	private static void throwExceptionIfPartNameNotStartsWithForwardSlashChar(
+			URI partUri) throws InvalidFormatException {
+		String uriPath = partUri.getPath();
+		if (uriPath.length() > 0
+				&& uriPath.charAt(0) != PackagingURIHelper.FORWARD_SLASH_CHAR)
+			throw new InvalidFormatException(
+					"A part name shall start with a forward slash ('/') character [M1.4]: "
+							+ partUri.getPath());
+	}
+
+	/**
+	 * Throws an exception if the specified part name ends with a forwar slash
+	 * character '/'. [M1.5]
+	 * 
+	 * @param partUri
+	 *            The part name to check.
+	 * @throws InvalidFormatException
+	 *             If the specified part name ends with a forwar slash character
+	 *             '/'.
+	 */
+	private static void throwExceptionIfPartNameEndsWithForwardSlashChar(
+			URI partUri) throws InvalidFormatException {
+		String uriPath = partUri.getPath();
+		if (uriPath.length() > 0
+				&& uriPath.charAt(uriPath.length() - 1) == PackagingURIHelper.FORWARD_SLASH_CHAR)
+			throw new InvalidFormatException(
+					"A part name shall not have a forward slash as the last character [M1.5]: "
+							+ partUri.getPath());
+	}
+
+	/**
+	 * Throws an exception if the specified URI is absolute.
+	 * 
+	 * @param partUri
+	 *            The URI to check.
+	 * @throws InvalidFormatException
+	 *             Throws if the specified URI is absolute.
+	 */
+	private static void throwExceptionIfAbsoluteUri(URI partUri)
+			throws InvalidFormatException {
+		if (partUri.isAbsolute())
+			throw new InvalidFormatException("Absolute URI forbidden: "
+					+ partUri);
+	}
+
+	/**
+	 * Compare two part name following the rule M1.12 :
+	 * 
+	 * Part name equivalence is determined by comparing part names as
+	 * case-insensitive ASCII strings. Packages shall not contain equivalent
+	 * part names and package implementers shall neither create nor recognize
+	 * packages with equivalent part names. [M1.12]
+	 */
+	public int compareTo(PackagePartName otherPartName) {
+		if (otherPartName == null)
+			return -1;
+		return this.partNameURI.toASCIIString().toLowerCase().compareTo(
+				otherPartName.partNameURI.toASCIIString().toLowerCase());
+	}
+
+	/**
+	 * Retrieves the extension of the part name if any. If there is no extension
+	 * returns an empty String. Example : '/document/content.xml' => 'xml'
+	 * 
+	 * @return The extension of the part name.
+	 */
+	public String getExtension() {
+		String fragment = this.partNameURI.getPath();
+		if (fragment.length() > 0) {
+			int i = fragment.lastIndexOf(".");
+			if (i > -1)
+				return fragment.substring(i + 1);
+		}
+		return "";
+	}
+
+	/**
+	 * Get this part name.
+	 * 
+	 * @return The name of this part name.
+	 */
+	public String getName() {
+		return this.partNameURI.toASCIIString();
+	}
+
+	/**
+	 * Part name equivalence is determined by comparing part names as
+	 * case-insensitive ASCII strings. Packages shall not contain equivalent
+	 * part names and package implementers shall neither create nor recognize
+	 * packages with equivalent part names. [M1.12]
+	 */
+	@Override
+	public boolean equals(Object otherPartName) {
+		if (otherPartName == null
+				|| !(otherPartName instanceof PackagePartName))
+			return false;
+		return this.partNameURI.toASCIIString().toLowerCase().equals(
+				((PackagePartName) otherPartName).partNameURI.toASCIIString()
+						.toLowerCase());
+	}
+
+	@Override
+	public int hashCode() {
+		return this.partNameURI.toASCIIString().toLowerCase().hashCode();
+	}
+
+	@Override
+	public String toString() {
+		return getName();
+	}
+
+	/* Getters and setters */
+
+	/**
+	 * Part name property getter.
+	 * 
+	 * @return This part name URI.
+	 */
+	public URI getURI() {
+		return this.partNameURI;
+	}
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartName.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageProperties.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageProperties.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageProperties.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageProperties.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,227 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc;
+
+import java.util.Date;
+
+import org.apache.poi.openxml4j.util.Nullable;
+
+/**
+ * Represents the core properties of an OPC package.
+ * 
+ * @author Julien Chable
+ * @version 1.0
+ * @see org.apache.poi.openxml4j.opc.Package
+ */
+public interface PackageProperties {
+	
+	/**
+	 * Dublin Core Terms URI.
+	 */
+	public final static String NAMESPACE_DCTERMS = "http://purl.org/dc/terms/";
+	
+	/**
+	 * Dublin Core namespace URI.
+	 */
+	public final static String NAMESPACE_DC = "http://purl.org/dc/elements/1.1/";
+
+	/* Getters and setters */
+
+	/**
+	 * Set the category of the content of this package.
+	 */
+	public abstract Nullable<String> getCategoryProperty();
+
+	/**
+	 * Set the category of the content of this package.
+	 */
+	public abstract void setCategoryProperty(String category);
+
+	/**
+	 * Set the status of the content.
+	 */
+	public abstract Nullable<String> getContentStatusProperty();
+
+	/**
+	 * Get the status of the content.
+	 */
+	public abstract void setContentStatusProperty(String contentStatus);
+
+	/**
+	 * Get the type of content represented, generally defined by a specific use
+	 * and intended audience.
+	 */
+	public abstract Nullable<String> getContentTypeProperty();
+
+	/**
+	 * Set the type of content represented, generally defined by a specific use
+	 * and intended audience.
+	 */
+	public abstract void setContentTypeProperty(String contentType);
+
+	/**
+	 * Get the date of creation of the resource.
+	 */
+	public abstract Nullable<Date> getCreatedProperty();
+
+	/**
+	 * Set the date of creation of the resource.
+	 */
+	public abstract void setCreatedProperty(String created);
+	
+	/**
+	 * Set the date of creation of the resource.
+	 */
+	public abstract void setCreatedProperty(Nullable<Date> created);
+
+	/**
+	 * Get the entity primarily responsible for making the content of the
+	 * resource.
+	 */
+	public abstract Nullable<String> getCreatorProperty();
+
+	/**
+	 * Set the entity primarily responsible for making the content of the
+	 * resource.
+	 */
+	public abstract void setCreatorProperty(String creator);
+
+	/**
+	 * Get the explanation of the content of the resource.
+	 */
+	public abstract Nullable<String> getDescriptionProperty();
+
+	/**
+	 * Set the explanation of the content of the resource.
+	 */
+	public abstract void setDescriptionProperty(String description);
+
+	/**
+	 * Get an unambiguous reference to the resource within a given context.
+	 */
+	public abstract Nullable<String> getIdentifierProperty();
+
+	/**
+	 * Set an unambiguous reference to the resource within a given context.
+	 */
+	public abstract void setIdentifierProperty(String identifier);
+
+	/**
+	 * Get a delimited set of keywords to support searching and indexing. This
+	 * is typically a list of terms that are not available elsewhere in the
+	 * properties
+	 */
+	public abstract Nullable<String> getKeywordsProperty();
+
+	/**
+	 * Set a delimited set of keywords to support searching and indexing. This
+	 * is typically a list of terms that are not available elsewhere in the
+	 * properties
+	 */
+	public abstract void setKeywordsProperty(String keywords);
+
+	/**
+	 * Get the language of the intellectual content of the resource.
+	 */
+	public abstract Nullable<String> getLanguageProperty();
+
+	/**
+	 * Set the language of the intellectual content of the resource.
+	 */
+	public abstract void setLanguageProperty(String language);
+
+	/**
+	 * Get the user who performed the last modification.
+	 */
+	public abstract Nullable<String> getLastModifiedByProperty();
+
+	/**
+	 * Set the user who performed the last modification.
+	 */
+	public abstract void setLastModifiedByProperty(String lastModifiedBy);
+
+	/**
+	 * Get the date and time of the last printing.
+	 */
+	public abstract Nullable<Date> getLastPrintedProperty();
+
+	/**
+	 * Set the date and time of the last printing.
+	 */
+	public abstract void setLastPrintedProperty(String lastPrinted);
+	
+	/**
+	 * Set the date and time of the last printing.
+	 */
+	public abstract void setLastPrintedProperty(Nullable<Date> lastPrinted);
+
+	/**
+	 * Get the date on which the resource was changed.
+	 */
+	public abstract Nullable<Date> getModifiedProperty();
+
+	/**
+	 * Set the date on which the resource was changed.
+	 */
+	public abstract void setModifiedProperty(String modified);
+	
+	/**
+	 * Set the date on which the resource was changed.
+	 */
+	public abstract void setModifiedProperty(Nullable<Date> modified);
+
+	/**
+	 * Get the revision number.
+	 */
+	public abstract Nullable<String> getRevisionProperty();
+
+	/**
+	 * Set the revision number.
+	 */
+	public abstract void setRevisionProperty(String revision);
+
+	/**
+	 * Get the topic of the content of the resource.
+	 */
+	public abstract Nullable<String> getSubjectProperty();
+
+	/**
+	 * Set the topic of the content of the resource.
+	 */
+	public abstract void setSubjectProperty(String subject);
+
+	/**
+	 * Get the name given to the resource.
+	 */
+	public abstract Nullable<String> getTitleProperty();
+
+	/**
+	 * Set the name given to the resource.
+	 */
+	public abstract void setTitleProperty(String title);
+
+	/**
+	 * Get the version number.
+	 */
+	public abstract Nullable<String> getVersionProperty();
+
+	/**
+	 * Set the version number.
+	 */
+	public abstract void setVersionProperty(String version);
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageProperties.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationship.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationship.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationship.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationship.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,227 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * A part relationship.
+ * 
+ * @author Julien Chable
+ * @version 1.0
+ */
+public final class PackageRelationship {
+
+	private static URI containerRelationshipPart;
+
+	static {
+		try {
+			containerRelationshipPart = new URI("/_rels/.rels");
+		} catch (URISyntaxException e) {
+			// Do nothing
+		}
+	}
+
+	/* XML markup */
+
+	public static final String ID_ATTRIBUTE_NAME = "Id";
+
+	public static final String RELATIONSHIPS_TAG_NAME = "Relationships";
+
+	public static final String RELATIONSHIP_TAG_NAME = "Relationship";
+
+	public static final String TARGET_ATTRIBUTE_NAME = "Target";
+
+	public static final String TARGET_MODE_ATTRIBUTE_NAME = "TargetMode";
+
+	public static final String TYPE_ATTRIBUTE_NAME = "Type";
+
+	/* End XML markup */
+
+	/**
+	 * L'ID de la relation.
+	 */
+	private String id;
+
+	/**
+	 * R�f�rence vers le package.
+	 */
+	private Package container;
+
+	/**
+	 * Type de relation.
+	 */
+	private String relationshipType;
+
+	/**
+	 * Partie source de cette relation.
+	 */
+	private PackagePart source;
+
+	/**
+	 * Le mode de ciblage [Internal|External]
+	 */
+	private TargetMode targetMode;
+
+	/**
+	 * URI de la partie cible.
+	 */
+	private URI targetUri;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param packageParent
+	 * @param sourcePart
+	 * @param targetUri
+	 * @param targetMode
+	 * @param relationshipType
+	 * @param id
+	 */
+	public PackageRelationship(Package pkg, PackagePart sourcePart,
+			URI targetUri, TargetMode targetMode, String relationshipType,
+			String id) {
+		if (pkg == null)
+			throw new IllegalArgumentException("pkg");
+		if (targetUri == null)
+			throw new IllegalArgumentException("targetUri");
+		if (relationshipType == null)
+			throw new IllegalArgumentException("relationshipType");
+		if (id == null)
+			throw new IllegalArgumentException("id");
+
+		this.container = pkg;
+		this.source = sourcePart;
+		this.targetUri = targetUri;
+		this.targetMode = targetMode;
+		this.relationshipType = relationshipType;
+		this.id = id;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (!(obj instanceof PackageRelationship)) {
+			return false;
+		}
+		PackageRelationship rel = (PackageRelationship) obj;
+		return (this.id == rel.id
+				&& this.relationshipType == rel.relationshipType
+				&& (rel.source != null ? rel.source.equals(this.source) : true)
+				&& this.targetMode == rel.targetMode && this.targetUri
+				.equals(rel.targetUri));
+	}
+
+	@Override
+	public int hashCode() {
+		return this.id.hashCode() + this.relationshipType.hashCode()
+				+ this.source.hashCode() + this.targetMode.hashCode()
+				+ this.targetUri.hashCode();
+	}
+
+	/* Getters */
+
+	public URI getContainerPartRelationship() {
+		return containerRelationshipPart;
+	}
+
+	/**
+	 * @return the container
+	 */
+	public Package getPackage() {
+		return container;
+	}
+
+	/**
+	 * @return the id
+	 */
+	public String getId() {
+		return id;
+	}
+
+	/**
+	 * @return the relationshipType
+	 */
+	public String getRelationshipType() {
+		return relationshipType;
+	}
+
+	/**
+	 * @return the source
+	 */
+	public PackagePart getSource() {
+		return source;
+	}
+
+	/**
+	 * 
+	 * @return
+	 */
+	public URI getSourceURI() {
+		if (source == null) {
+			return PackagingURIHelper.PACKAGE_ROOT_URI;
+		}
+		return source.partName.getURI();
+	}
+
+	/**
+	 * public URI getSourceUri(){ }
+	 * 
+	 * @return the targetMode
+	 */
+	public TargetMode getTargetMode() {
+		return targetMode;
+	}
+
+	/**
+	 * @return the targetUri
+	 */
+	public URI getTargetURI() {
+		// If it's an external target, we don't
+		//  need to apply our normal validation rules
+		if(targetMode == TargetMode.EXTERNAL) {
+			return targetUri;
+		}
+		
+		// Internal target
+		// If it isn't absolute, resolve it relative
+		//  to ourselves
+		if (!targetUri.toASCIIString().startsWith("/")) {
+			// So it's a relative part name, try to resolve it
+			return PackagingURIHelper.resolvePartUri(getSourceURI(), targetUri);
+		}
+		return targetUri;
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+		sb.append(id == null ? "id=null" : "id=" + id);
+		sb.append(container == null ? " - container=null" : " - container="
+				+ container.toString());
+		sb.append(relationshipType == null ? " - relationshipType=null"
+				: " - relationshipType=" + relationshipType.toString());
+		sb.append(source == null ? " - source=null" : " - source="
+				+ getSourceURI().toASCIIString());
+		sb.append(targetUri == null ? " - target=null" : " - target="
+				+ getTargetURI().toASCIIString());
+		sb.append(targetMode == null ? ",targetMode=null" : ",targetMode="
+				+ targetMode.toString());
+		return sb.toString();
+	}
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationship.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,450 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.openxml4j.opc;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.TreeMap;
+
+import org.apache.log4j.Logger;
+import org.dom4j.Attribute;
+import org.dom4j.Document;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
+
+/**
+ * Represents a collection of PackageRelationship elements that are owned by a
+ * given PackagePart or the Package.
+ * 
+ * @author Julien Chable, CDubettier
+ * @version 0.1
+ */
+public final class PackageRelationshipCollection implements
+		Iterable<PackageRelationship> {
+
+	private static Logger logger = Logger.getLogger("org.openxml4j.opc");
+
+	/**
+	 * Package relationships ordered by ID.
+	 */
+	private TreeMap<String, PackageRelationship> relationshipsByID;
+
+	/**
+	 * Package relationships ordered by type.
+	 */
+	private TreeMap<String, PackageRelationship> relationshipsByType;
+
+	/**
+	 * This relationshipPart.
+	 */
+	private PackagePart relationshipPart;
+
+	/**
+	 * Source part.
+	 */
+	private PackagePart sourcePart;
+
+	/**
+	 * This part name.
+	 */
+	private PackagePartName partName;
+
+	/**
+	 * Reference to the package.
+	 */
+	private Package container;
+
+	/**
+	 * Constructor.
+	 */
+	PackageRelationshipCollection() {
+		relationshipsByID = new TreeMap<String, PackageRelationship>();
+		relationshipsByType = new TreeMap<String, PackageRelationship>();
+	}
+
+	/**
+	 * Copy constructor.
+	 * 
+	 * This collection will contain only elements from the specified collection
+	 * for which the type is compatible with the specified relationship type
+	 * filter.
+	 * 
+	 * @param coll
+	 *            Collection to import.
+	 * @param filter
+	 *            Relationship type filter.
+	 */
+	public PackageRelationshipCollection(PackageRelationshipCollection coll,
+			String filter) {
+		this();
+		for (PackageRelationship rel : coll.relationshipsByID.values()) {
+			if (filter == null || rel.getRelationshipType().equals(filter))
+				addRelationship(rel);
+		}
+	}
+
+	/**
+	 * Constructor.
+	 */
+	public PackageRelationshipCollection(Package container)
+			throws InvalidFormatException {
+		this(container, null);
+	}
+
+	/**
+	 * Constructor.
+	 * 
+	 * @throws InvalidFormatException
+	 *             Throws if the format of the content part is invalid.
+	 * 
+	 * @throws InvalidOperationException
+	 *             Throws if the specified part is a relationship part.
+	 */
+	public PackageRelationshipCollection(PackagePart part)
+			throws InvalidFormatException {
+		this(part.container, part);
+	}
+
+	/**
+	 * Constructor. Parse the existing package relationship part if one exists.
+	 * 
+	 * @param container
+	 *            The parent package.
+	 * @param part
+	 *            The part that own this relationships collection. If <b>null</b>
+	 *            then this part is considered as the package root.
+	 * @throws InvalidFormatException
+	 *             If an error occurs during the parsing of the relatinships
+	 *             part fo the specified part.
+	 */
+	public PackageRelationshipCollection(Package container, PackagePart part)
+			throws InvalidFormatException {
+		this();
+
+		if (container == null)
+			throw new IllegalArgumentException("container");
+
+		// Check if the specified part is not a relationship part
+		if (part != null && part.isRelationshipPart())
+			throw new IllegalArgumentException("part");
+
+		this.container = container;
+		this.sourcePart = part;
+		this.partName = getRelationshipPartName(part);
+		if ((container.getPackageAccess() != PackageAccess.WRITE)
+				&& container.containPart(this.partName)) {
+			relationshipPart = container.getPart(this.partName);
+			parseRelationshipsPart(relationshipPart);
+		}
+	}
+
+	/**
+	 * Get the relationship part name of the specified part.
+	 * 
+	 * @param part
+	 *            The part .
+	 * @return The relationship part name of the specified part. Be careful,
+	 *         only the correct name is returned, this method does not check if
+	 *         the part really exist in a package !
+	 * @throws InvalidOperationException
+	 *             Throws if the specified part is a relationship part.
+	 */
+	private static PackagePartName getRelationshipPartName(PackagePart part)
+			throws InvalidOperationException {
+		PackagePartName partName;
+		if (part == null) {
+			partName = PackagingURIHelper.PACKAGE_ROOT_PART_NAME;
+		} else {
+			partName = part.getPartName();
+		}
+		return PackagingURIHelper.getRelationshipPartName(partName);
+	}
+
+	/**
+	 * Add the specified relationship to the collection.
+	 * 
+	 * @param relPart
+	 *            The relationship to add.
+	 */
+	public void addRelationship(PackageRelationship relPart) {
+		relationshipsByID.put(relPart.getId(), relPart);
+		relationshipsByType.put(relPart.getRelationshipType(), relPart);
+	}
+
+	/**
+	 * Add a relationship to the collection.
+	 * 
+	 * @param targetUri
+	 *            Target URI.
+	 * @param targetMode
+	 *            The target mode : INTERNAL or EXTERNAL
+	 * @param relationshipType
+	 *            Relationship type.
+	 * @param id
+	 *            Relationship ID.
+	 * @return The newly created relationship.
+	 * @see PackageAccess
+	 */
+	public PackageRelationship addRelationship(URI targetUri,
+			TargetMode targetMode, String relationshipType, String id) {
+
+		if (id == null) {
+			// Generate a unique ID is id parameter is null.
+			int i = 0;
+			do {
+				id = "rId" + ++i;
+			} while (relationshipsByID.get(id) != null);
+		}
+
+		PackageRelationship rel = new PackageRelationship(container,
+				sourcePart, targetUri, targetMode, relationshipType, id);
+		relationshipsByID.put(rel.getId(), rel);
+		relationshipsByType.put(rel.getRelationshipType(), rel);
+		return rel;
+	}
+
+	/**
+	 * Remove a relationship by its ID.
+	 * 
+	 * @param id
+	 *            The relationship ID to remove.
+	 */
+	public void removeRelationship(String id) {
+		if (relationshipsByID != null && relationshipsByType != null) {
+			PackageRelationship rel = relationshipsByID.get(id);
+			if (rel != null) {
+				relationshipsByID.remove(rel.getId());
+				relationshipsByType.values().remove(rel);
+			}
+		}
+	}
+
+	/**
+	 * Remove a relationship by its reference.
+	 * 
+	 * @param rel
+	 *            The relationship to delete.
+	 */
+	public void removeRelationship(PackageRelationship rel) {
+		if (rel == null)
+			throw new IllegalArgumentException("rel");
+
+		relationshipsByID.values().remove(rel);
+		relationshipsByType.values().remove(rel);
+	}
+
+	/**
+	 * Retrieves a relationship by its index in the collection.
+	 * 
+	 * @param index
+	 *            Must be a value between [0-relationships_count-1]
+	 */
+	public PackageRelationship getRelationship(int index) {
+		if (index < 0 || index > relationshipsByID.values().size())
+			throw new IllegalArgumentException("index");
+
+		PackageRelationship retRel = null;
+		int i = 0;
+		for (PackageRelationship rel : relationshipsByID.values()) {
+			if (index == i++)
+				return rel;
+		}
+		return retRel;
+	}
+
+	/**
+	 * Retrieves a package relationship based on its id.
+	 * 
+	 * @param id
+	 *            ID of the package relationship to retrieve.
+	 * @return The package relationship identified by the specified id.
+	 */
+	public PackageRelationship getRelationshipByID(String id) {
+		return relationshipsByID.get(id);
+	}
+
+	/**
+	 * Get the numbe rof relationships in the collection.
+	 */
+	public int size() {
+		return relationshipsByID.values().size();
+	}
+
+	/**
+	 * Parse the relationship part and add all relationship in this collection.
+	 * 
+	 * @param relPart
+	 *            The package part to parse.
+	 * @throws InvalidFormatException
+	 *             Throws if the relationship part is invalid.
+	 */
+	private void parseRelationshipsPart(PackagePart relPart)
+			throws InvalidFormatException {
+		try {
+			SAXReader reader = new SAXReader();
+			logger.debug("Parsing relationship: " + relPart.getPartName());
+			Document xmlRelationshipsDoc = reader
+					.read(relPart.getInputStream());
+
+			// Browse default types
+			Element root = xmlRelationshipsDoc.getRootElement();
+
+			// Check OPC compliance M4.1 rule
+			boolean fCorePropertiesRelationship = false;
+
+			for (Iterator i = root
+					.elementIterator(PackageRelationship.RELATIONSHIP_TAG_NAME); i
+					.hasNext();) {
+				Element element = (Element) i.next();
+				// Relationship ID
+				String id = element.attribute(
+						PackageRelationship.ID_ATTRIBUTE_NAME).getValue();
+				// Relationship type
+				String type = element.attribute(
+						PackageRelationship.TYPE_ATTRIBUTE_NAME).getValue();
+
+				/* Check OPC Compliance */
+				// Check Rule M4.1
+				if (type.equals(PackageRelationshipTypes.CORE_PROPERTIES))
+					if (!fCorePropertiesRelationship)
+						fCorePropertiesRelationship = true;
+					else
+						throw new InvalidFormatException(
+								"OPC Compliance error [M4.1]: there is more than one core properties relationship in the package !");
+
+				/* End OPC Compliance */
+
+				// TargetMode (default value "Internal")
+				Attribute targetModeAttr = element
+						.attribute(PackageRelationship.TARGET_MODE_ATTRIBUTE_NAME);
+				TargetMode targetMode = TargetMode.INTERNAL;
+				if (targetModeAttr != null) {
+					targetMode = targetModeAttr.getValue().toLowerCase()
+							.equals("internal") ? TargetMode.INTERNAL
+							: TargetMode.EXTERNAL;
+				}
+
+				// Target converted in URI
+				URI target;
+				String value = "";
+				try {
+					value = element.attribute(
+							PackageRelationship.TARGET_ATTRIBUTE_NAME)
+							.getValue();
+
+					if (value.indexOf("\\") != -1) {
+						logger
+								.info("target contains \\ therefore not a valid URI"
+										+ value + " replaced by /");
+						value = value.replaceAll("\\\\", "/");
+						// word can save external relationship with a \ instead
+						// of /
+					}
+
+					target = new URI(value);
+				} catch (URISyntaxException e) {
+					logger.error("Cannot convert " + value
+							+ " in a valid relationship URI-> ignored", e);
+					continue;
+				}
+				addRelationship(target, targetMode, type, id);
+			}
+		} catch (Exception e) {
+			logger.error(e);
+			throw new InvalidFormatException(e.getMessage());
+		}
+	}
+
+	/**
+	 * Retrieves all relations with the specified type.
+	 * 
+	 * @param typeFilter
+	 *            Relationship type filter. If <b>null</b> then all
+	 *            relationships are returned.
+	 * @return All relationships of the type specified by the filter.
+	 */
+	public PackageRelationshipCollection getRelationships(String typeFilter) {
+		PackageRelationshipCollection coll = new PackageRelationshipCollection(
+				this, typeFilter);
+		return coll;
+	}
+
+	/**
+	 * Get this collection's iterator.
+	 */
+	public Iterator<PackageRelationship> iterator() {
+		return relationshipsByID.values().iterator();
+	}
+
+	/**
+	 * Get an iterator of a collection with all relationship with the specified
+	 * type.
+	 * 
+	 * @param typeFilter
+	 *            Type filter.
+	 * @return An iterator to a collection containing all relationships with the
+	 *         specified type contain in this collection.
+	 */
+	public Iterator<PackageRelationship> iterator(String typeFilter) {
+		ArrayList<PackageRelationship> retArr = new ArrayList<PackageRelationship>();
+		for (PackageRelationship rel : relationshipsByID.values()) {
+			if (rel.getRelationshipType().equals(typeFilter))
+				retArr.add(rel);
+		}
+		return retArr.iterator();
+	}
+
+	/**
+	 * Clear all relationships.
+	 */
+	public void clear() {
+		relationshipsByID.clear();
+		relationshipsByType.clear();
+	}
+
+	@Override
+	public String toString() {
+		String str;
+		if (relationshipsByID == null) {
+			str = "relationshipsByID=null";
+		} else {
+			str = relationshipsByID.size() + " relationship(s) = [";
+		}
+		if ((relationshipPart != null) && (relationshipPart.partName != null)) {
+			str = str + "," + relationshipPart.partName;
+		} else {
+			str = str + ",relationshipPart=null";
+		}
+
+		// Source of this relationship
+		if ((sourcePart != null) && (sourcePart.partName != null)) {
+			str = str + "," + sourcePart.partName;
+		} else {
+			str = str + ",sourcePart=null";
+		}
+		if (partName != null) {
+			str = str + "," + partName;
+		} else {
+			str = str + ",uri=null)";
+		}
+		return str + "]";
+	}
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipTypes.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipTypes.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipTypes.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipTypes.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,77 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc;
+
+/**
+ * Relationship types.
+ * 
+ * @author Julien Chable
+ * @version 0.2
+ */
+public interface PackageRelationshipTypes {
+
+	/**
+	 * Core properties relationship type.
+	 */
+	String CORE_PROPERTIES = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
+
+	/**
+	 * Digital signature relationship type.
+	 */
+	String DIGITAL_SIGNATURE = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/signature";
+
+	/**
+	 * Digital signature certificate relationship type.
+	 */
+	String DIGITAL_SIGNATURE_CERTIFICATE = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/certificate";
+
+	/**
+	 * Digital signature origin relationship type.
+	 */
+	String DIGITAL_SIGNATURE_ORIGIN = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin";
+
+	/**
+	 * Thumbnail relationship type.
+	 */
+	String THUMBNAIL = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
+
+	/**
+	 * Extended properties relationship type.
+	 */
+	String EXTENDED_PROPERTIES = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
+
+	/**
+	 * Core properties relationship type.
+	 */
+	String CORE_DOCUMENT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
+	
+	/**
+	 * Custom XML relationship type.
+	 */
+	String CUSTOM_XML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml";
+
+	/**
+	 * Image type.
+	 */
+	String IMAGE_PART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
+
+	/**
+	 * Style type.
+	 */
+	String STYLE_PART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipTypes.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagingURIHelper.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagingURIHelper.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagingURIHelper.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagingURIHelper.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,623 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
+
+/**
+ * Helper for part and pack URI.
+ * 
+ * @author Julien Chable, CDubet, Kim Ung
+ * @version 0.1
+ */
+public final class PackagingURIHelper {
+
+	/**
+	 * Package root URI.
+	 */
+	private static URI packageRootUri;
+
+	/**
+	 * Extension name of a relationship part.
+	 */
+	public static final String RELATIONSHIP_PART_EXTENSION_NAME;
+
+	/**
+	 * Segment name of a relationship part.
+	 */
+	public static final String RELATIONSHIP_PART_SEGMENT_NAME;
+
+	/**
+	 * Segment name of the package properties folder.
+	 */
+	public static final String PACKAGE_PROPERTIES_SEGMENT_NAME;
+
+	/**
+	 * Core package properties art name.
+	 */
+	public static final String PACKAGE_CORE_PROPERTIES_NAME;
+
+	/**
+	 * Forward slash URI separator.
+	 */
+	public static final char FORWARD_SLASH_CHAR;
+
+	/**
+	 * Forward slash URI separator.
+	 */
+	public static final String FORWARD_SLASH_STRING;
+
+	/**
+	 * Package relationships part URI
+	 */
+	public static final URI PACKAGE_RELATIONSHIPS_ROOT_URI;
+
+	/**
+	 * Package relationships part name.
+	 */
+	public static final PackagePartName PACKAGE_RELATIONSHIPS_ROOT_PART_NAME;
+
+	/**
+	 * Core properties part URI.
+	 */
+	public static final URI CORE_PROPERTIES_URI;
+
+	/**
+	 * Core properties partname.
+	 */
+	public static final PackagePartName CORE_PROPERTIES_PART_NAME;
+
+	/**
+	 * Root package URI.
+	 */
+	public static final URI PACKAGE_ROOT_URI;
+
+	/**
+	 * Root package part name.
+	 */
+	public static final PackagePartName PACKAGE_ROOT_PART_NAME;
+
+	/* Static initialization */
+	static {
+		RELATIONSHIP_PART_SEGMENT_NAME = "_rels";
+		RELATIONSHIP_PART_EXTENSION_NAME = ".rels";
+		FORWARD_SLASH_CHAR = '/';
+		FORWARD_SLASH_STRING = "/";
+		PACKAGE_PROPERTIES_SEGMENT_NAME = "docProps";
+		PACKAGE_CORE_PROPERTIES_NAME = "core.xml";
+
+		// Make URI
+		URI uriPACKAGE_ROOT_URI = null;
+		URI uriPACKAGE_RELATIONSHIPS_ROOT_URI = null;
+		URI uriPACKAGE_PROPERTIES_URI = null;
+		try {
+			uriPACKAGE_ROOT_URI = new URI("/");
+			uriPACKAGE_RELATIONSHIPS_ROOT_URI = new URI(FORWARD_SLASH_CHAR
+					+ RELATIONSHIP_PART_SEGMENT_NAME + FORWARD_SLASH_CHAR
+					+ RELATIONSHIP_PART_EXTENSION_NAME);
+			packageRootUri = new URI("/");
+			uriPACKAGE_PROPERTIES_URI = new URI(FORWARD_SLASH_CHAR
+					+ PACKAGE_PROPERTIES_SEGMENT_NAME + FORWARD_SLASH_CHAR
+					+ PACKAGE_CORE_PROPERTIES_NAME);
+		} catch (URISyntaxException e) {
+			// Should never happen in production as all data are fixed
+		}
+		PACKAGE_ROOT_URI = uriPACKAGE_ROOT_URI;
+		PACKAGE_RELATIONSHIPS_ROOT_URI = uriPACKAGE_RELATIONSHIPS_ROOT_URI;
+		CORE_PROPERTIES_URI = uriPACKAGE_PROPERTIES_URI;
+
+		// Make part name from previous URI
+		PackagePartName tmpPACKAGE_ROOT_PART_NAME = null;
+		PackagePartName tmpPACKAGE_RELATIONSHIPS_ROOT_PART_NAME = null;
+		PackagePartName tmpCORE_PROPERTIES_URI = null;
+		try {
+			tmpPACKAGE_RELATIONSHIPS_ROOT_PART_NAME = createPartName(PACKAGE_RELATIONSHIPS_ROOT_URI);
+			tmpCORE_PROPERTIES_URI = createPartName(CORE_PROPERTIES_URI);
+			tmpPACKAGE_ROOT_PART_NAME = new PackagePartName(PACKAGE_ROOT_URI,
+					false);
+		} catch (InvalidFormatException e) {
+			// Should never happen in production as all data are fixed
+		}
+		PACKAGE_RELATIONSHIPS_ROOT_PART_NAME = tmpPACKAGE_RELATIONSHIPS_ROOT_PART_NAME;
+		CORE_PROPERTIES_PART_NAME = tmpCORE_PROPERTIES_URI;
+		PACKAGE_ROOT_PART_NAME = tmpPACKAGE_ROOT_PART_NAME;
+	}
+
+	/**
+	 * Gets the URI for the package root.
+	 * 
+	 * @return URI of the package root.
+	 */
+	public static URI getPackageRootUri() {
+		return packageRootUri;
+	}
+
+	/**
+	 * Know if the specified URI is a relationship part name.
+	 * 
+	 * @param partUri
+	 *            URI to check.
+	 * @return <i>true</i> if the URI <i>false</i>.
+	 */
+	public static boolean isRelationshipPartURI(URI partUri) {
+		if (partUri == null)
+			throw new IllegalArgumentException("partUri");
+
+		return partUri.getPath().matches(
+				".*" + RELATIONSHIP_PART_SEGMENT_NAME + ".*"
+						+ RELATIONSHIP_PART_EXTENSION_NAME + "$");
+	}
+
+	/**
+	 * Get file name from the specified URI.
+	 */
+	public static String getFilename(URI uri) {
+		if (uri != null) {
+			String path = uri.getPath();
+			int len = path.length();
+			int num2 = len;
+			while (--num2 >= 0) {
+				char ch1 = path.charAt(num2);
+				if (ch1 == PackagingURIHelper.FORWARD_SLASH_CHAR)
+					return path.substring(num2 + 1, len);
+			}
+		}
+		return "";
+	}
+
+	/**
+	 * Get the file name without the trailing extension.
+	 */
+	public static String getFilenameWithoutExtension(URI uri) {
+		String filename = getFilename(uri);
+		int dotIndex = filename.lastIndexOf(".");
+		if (dotIndex == -1)
+			return filename;
+		return filename.substring(0, dotIndex);
+	}
+
+	/**
+	 * Get the directory path from the specified URI.
+	 */
+	public static URI getPath(URI uri) {
+		if (uri != null) {
+			String path = uri.getPath();
+			int len = path.length();
+			int num2 = len;
+			while (--num2 >= 0) {
+				char ch1 = path.charAt(num2);
+				if (ch1 == PackagingURIHelper.FORWARD_SLASH_CHAR) {
+					try {
+						return new URI(path.substring(0, num2));
+					} catch (URISyntaxException e) {
+						return null;
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Combine les deux URI.
+	 * 
+	 * @param prefix
+	 *            L'URI de pr�fixe.
+	 * @param suffix
+	 *            L'URI de suffixe.
+	 * @return
+	 */
+	public static URI combine(URI prefix, URI suffix) {
+		URI retUri = null;
+		try {
+			retUri = new URI(combine(prefix.getPath(), suffix.getPath()));
+		} catch (URISyntaxException e) {
+			throw new IllegalArgumentException(
+					"Prefix and suffix can't be combine !");
+		}
+		return retUri;
+	}
+
+	/**
+	 * Combine a string URI with a prefix and a suffix.
+	 */
+	public static String combine(String prefix, String suffix) {
+		if (!prefix.endsWith("" + FORWARD_SLASH_CHAR)
+				&& !suffix.startsWith("" + FORWARD_SLASH_CHAR))
+			return prefix + FORWARD_SLASH_CHAR + suffix;
+		else if ((!prefix.endsWith("" + FORWARD_SLASH_CHAR)
+				&& suffix.startsWith("" + FORWARD_SLASH_CHAR) || (prefix
+				.endsWith("" + FORWARD_SLASH_CHAR) && !suffix.startsWith(""
+				+ FORWARD_SLASH_CHAR))))
+			return prefix + suffix;
+		else
+			return "";
+	}
+
+	/**
+	 * Fully relativize the source part URI against the target part URI.
+	 * 
+	 * @param sourceURI
+	 *            The source part URI.
+	 * @param targetURI
+	 *            The target part URI.
+	 * @return A fully relativize part name URI ('word/media/image1.gif',
+	 *         '/word/document.xml' => 'media/image1.gif') else
+	 *         <code>null</code>.
+	 */
+	public static URI relativizeURI(URI sourceURI, URI targetURI) {
+		StringBuilder retVal = new StringBuilder();
+		String[] segmentsSource = sourceURI.getPath().split("/", -1);
+		String[] segmentsTarget = targetURI.getPath().split("/", -1);
+
+		// If the source URI is empty
+		if (segmentsSource.length == 0) {
+			throw new IllegalArgumentException(
+					"Can't relativize an empty source URI !");
+		}
+
+		// If target URI is empty
+		if (segmentsTarget.length == 0) {
+			throw new IllegalArgumentException(
+					"Can't relativize an empty target URI !");
+		}
+		
+		// If the source is the root, then the relativized
+		//  form must actually be an absolute URI
+		if(sourceURI.toString().equals("/")) {
+			return targetURI;
+		}
+
+
+		// Relativize the source URI against the target URI.
+		// First up, figure out how many steps along we can go
+		// and still have them be the same
+		int segmentsTheSame = 0;
+		for (int i = 0; i < segmentsSource.length && i < segmentsTarget.length; i++) {
+			if (segmentsSource[i].equals(segmentsTarget[i])) {
+				// Match so far, good
+				segmentsTheSame++;
+			} else {
+				break;
+			}
+		}
+
+		// If we didn't have a good match or at least except a first empty element
+		if ((segmentsTheSame == 0 || segmentsTheSame == 1) && 
+				segmentsSource[0].equals("") && segmentsTarget[0].equals("")) {
+			for (int i = 0; i < segmentsSource.length - 2; i++) {
+				retVal.append("../");
+			}
+			for (int i = 0; i < segmentsTarget.length; i++) {
+				if (segmentsTarget[i].equals(""))
+					continue;
+				retVal.append(segmentsTarget[i]);
+				if (i != segmentsTarget.length - 1)
+					retVal.append("/");
+			}
+
+			try {
+				return new URI(retVal.toString());
+			} catch (Exception e) {
+				System.err.println(e);
+				return null;
+			}
+		}
+
+		// Special case for where the two are the same
+		if (segmentsTheSame == segmentsSource.length
+				&& segmentsTheSame == segmentsTarget.length) {
+			retVal.append("");
+		} else {
+			// Matched for so long, but no more
+
+			// Do we need to go up a directory or two from
+			// the source to get here?
+			// (If it's all the way up, then don't bother!)
+			if (segmentsTheSame == 1) {
+				retVal.append("/");
+			} else {
+				for (int j = segmentsTheSame; j < segmentsSource.length - 1; j++) {
+					retVal.append("../");
+				}
+			}
+
+			// Now go from here on down
+			for (int j = segmentsTheSame; j < segmentsTarget.length; j++) {
+				if (retVal.length() > 0
+						&& retVal.charAt(retVal.length() - 1) != '/') {
+					retVal.append("/");
+				}
+				retVal.append(segmentsTarget[j]);
+			}
+		}
+
+		try {
+			return new URI(retVal.toString());
+		} catch (Exception e) {
+			System.err.println(e);
+			return null;
+		}
+	}
+
+	/**
+	 * Resolve a source uri against a target.
+	 * 
+	 * @param sourcePartUri
+	 *            The source URI.
+	 * @param targetUri
+	 *            The target URI.
+	 * @return The resolved URI.
+	 */
+	public static URI resolvePartUri(URI sourcePartUri, URI targetUri) {
+		if (sourcePartUri == null || sourcePartUri.isAbsolute()) {
+			throw new IllegalArgumentException("sourcePartUri invalid - "
+					+ sourcePartUri);
+		}
+
+		if (targetUri == null || targetUri.isAbsolute()) {
+			throw new IllegalArgumentException("targetUri invalid - "
+					+ targetUri);
+		}
+
+		return sourcePartUri.resolve(targetUri);
+	}
+
+	/**
+	 * Get URI from a string path.
+	 */
+	public static URI getURIFromPath(String path) {
+		URI retUri = null;
+		try {
+			retUri = new URI(path);
+		} catch (URISyntaxException e) {
+			throw new IllegalArgumentException("path");
+		}
+		return retUri;
+	}
+
+	/**
+	 * Get the source part URI from a specified relationships part.
+	 * 
+	 * @param relationshipPartUri
+	 *            The relationship part use to retrieve the source part.
+	 * @return The source part URI from the specified relationships part.
+	 */
+	public static URI getSourcePartUriFromRelationshipPartUri(
+			URI relationshipPartUri) {
+		if (relationshipPartUri == null)
+			throw new IllegalArgumentException(
+					"Le param�tre relationshipPartUri ne doit pas �tre null !");
+
+		if (!isRelationshipPartURI(relationshipPartUri))
+			throw new IllegalArgumentException(
+					"L'URI ne doit pas �tre celle d'une partie de type relation.");
+
+		if (relationshipPartUri.compareTo(PACKAGE_RELATIONSHIPS_ROOT_URI) == 0)
+			return PACKAGE_ROOT_URI;
+
+		String filename = relationshipPartUri.getPath();
+		String filenameWithoutExtension = getFilenameWithoutExtension(relationshipPartUri);
+		filename = filename
+				.substring(0, ((filename.length() - filenameWithoutExtension
+						.length()) - RELATIONSHIP_PART_EXTENSION_NAME.length()));
+		filename = filename.substring(0, filename.length()
+				- RELATIONSHIP_PART_SEGMENT_NAME.length() - 1);
+		filename = combine(filename, filenameWithoutExtension);
+		return getURIFromPath(filename);
+	}
+
+	/**
+	 * Create an OPC compliant part name by throwing an exception if the URI is
+	 * not valid.
+	 * 
+	 * @param partUri
+	 *            The part name URI to validate.
+	 * @return A valid part name object, else <code>null</code>.
+	 * @throws InvalidFormatException
+	 *             Throws if the specified URI is not OPC compliant.
+	 */
+	public static PackagePartName createPartName(URI partUri)
+			throws InvalidFormatException {
+		if (partUri == null)
+			throw new IllegalArgumentException("partName");
+
+		return new PackagePartName(partUri, true);
+	}
+
+	/**
+	 * Create an OPC compliant part name.
+	 * 
+	 * @param partName
+	 *            The part name to validate.
+	 * @return The correspondant part name if valid, else <code>null</code>.
+	 * @throws InvalidFormatException
+	 *             Throws if the specified part name is not OPC compliant.
+	 * @see #createPartName(URI)
+	 */
+	public static PackagePartName createPartName(String partName)
+			throws InvalidFormatException {
+		URI partNameURI;
+		try {
+			partNameURI = new URI(partName);
+		} catch (URISyntaxException e) {
+			throw new InvalidFormatException(e.getMessage());
+		}
+		return createPartName(partNameURI);
+	}
+
+	/**
+	 * Create an OPC compliant part name by resolving it using a base part.
+	 * 
+	 * @param partName
+	 *            The part name to validate.
+	 * @param relativePart
+	 *            The relative base part.
+	 * @return The correspondant part name if valid, else <code>null</code>.
+	 * @throws InvalidFormatException
+	 *             Throws if the specified part name is not OPC compliant.
+	 * @see #createPartName(URI)
+	 */
+	public static PackagePartName createPartName(String partName,
+			PackagePart relativePart) throws InvalidFormatException {
+		URI newPartNameURI;
+		try {
+			newPartNameURI = resolvePartUri(
+					relativePart.getPartName().getURI(), new URI(partName));
+		} catch (URISyntaxException e) {
+			throw new InvalidFormatException(e.getMessage());
+		}
+		return createPartName(newPartNameURI);
+	}
+
+	/**
+	 * Create an OPC compliant part name by resolving it using a base part.
+	 * 
+	 * @param partName
+	 *            The part name URI to validate.
+	 * @param relativePart
+	 *            The relative base part.
+	 * @return The correspondant part name if valid, else <code>null</code>.
+	 * @throws InvalidFormatException
+	 *             Throws if the specified part name is not OPC compliant.
+	 * @see #createPartName(URI)
+	 */
+	public static PackagePartName createPartName(URI partName,
+			PackagePart relativePart) throws InvalidFormatException {
+		URI newPartNameURI = resolvePartUri(
+				relativePart.getPartName().getURI(), partName);
+		return createPartName(newPartNameURI);
+	}
+
+	/**
+	 * Validate a part URI by returning a boolean.
+	 * ([M1.1],[M1.3],[M1.4],[M1.5],[M1.6])
+	 * 
+	 * (OPC Specifications 8.1.1 Part names) :
+	 * 
+	 * Part Name Syntax
+	 * 
+	 * The part name grammar is defined as follows:
+	 * 
+	 * <i>part_name = 1*( "/" segment )
+	 * 
+	 * segment = 1*( pchar )</i>
+	 * 
+	 * 
+	 * (pchar is defined in RFC 3986)
+	 * 
+	 * @param partUri
+	 *            The URI to validate.
+	 * @return <b>true</b> if the URI is valid to the OPC Specifications, else
+	 *         <b>false</b>
+	 * 
+	 * @see #createPartName(URI)
+	 */
+	public static boolean isValidPartName(URI partUri) {
+		if (partUri == null)
+			throw new IllegalArgumentException("partUri");
+
+		try {
+			createPartName(partUri);
+			return true;
+		} catch (Exception e) {
+			return false;
+		}
+	}
+
+	/**
+	 * Decode a URI by converting all percent encoded character into a String
+	 * character.
+	 * 
+	 * @param uri
+	 *            The URI to decode.
+	 * @return The specified URI in a String with converted percent encoded
+	 *         characters.
+	 */
+	public static String decodeURI(URI uri) {
+		StringBuffer retVal = new StringBuffer();
+		String uriStr = uri.toASCIIString();
+		char c;
+		for (int i = 0; i < uriStr.length(); ++i) {
+			c = uriStr.charAt(i);
+			if (c == '%') {
+				// We certainly found an encoded character, check for length
+				// now ( '%' HEXDIGIT HEXDIGIT)
+				if (((uriStr.length() - i) < 2)) {
+					throw new IllegalArgumentException("The uri " + uriStr
+							+ " contain invalid encoded character !");
+				}
+
+				// Decode the encoded character
+				char decodedChar = (char) Integer.parseInt(uriStr.substring(
+						i + 1, i + 3), 16);
+				retVal.append(decodedChar);
+				i += 2;
+				continue;
+			}
+			retVal.append(c);
+		}
+		return retVal.toString();
+	}
+
+	/**
+	 * Build a part name where the relationship should be stored ((ex
+	 * /word/document.xml -> /word/_rels/document.xml.rels)
+	 * 
+	 * @param partName
+	 *            Source part URI
+	 * @return the full path (as URI) of the relation file
+	 * @throws InvalidOperationException
+	 *             Throws if the specified URI is a relationshp part.
+	 */
+	public static PackagePartName getRelationshipPartName(
+			PackagePartName partName) {
+		if (partName == null)
+			throw new IllegalArgumentException("partName");
+
+		if (PackagingURIHelper.PACKAGE_ROOT_URI.getPath() == partName.getURI()
+				.getPath())
+			return PackagingURIHelper.PACKAGE_RELATIONSHIPS_ROOT_PART_NAME;
+
+		if (partName.isRelationshipPartURI())
+			throw new InvalidOperationException("Can't be a relationship part");
+
+		String fullPath = partName.getURI().getPath();
+		String filename = getFilename(partName.getURI());
+		fullPath = fullPath.substring(0, fullPath.length() - filename.length());
+		fullPath = combine(fullPath,
+				PackagingURIHelper.RELATIONSHIP_PART_SEGMENT_NAME);
+		fullPath = combine(fullPath, filename);
+		fullPath = fullPath
+				+ PackagingURIHelper.RELATIONSHIP_PART_EXTENSION_NAME;
+
+		PackagePartName retPartName;
+		try {
+			retPartName = createPartName(fullPath);
+		} catch (InvalidFormatException e) {
+			// Should never happen in production as all data are fixed but in
+			// case of return null:
+			return null;
+		}
+		return retPartName;
+	}
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagingURIHelper.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/RelationshipSource.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/RelationshipSource.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/RelationshipSource.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/RelationshipSource.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,166 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.openxml4j.opc;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+
+public interface RelationshipSource {
+
+	/**
+	 * Add a relationship to a part (except relationships part).
+	 * 
+	 * @param targetPartName
+	 *            Name of the target part. This one must be relative to the
+	 *            source root directory of the part.
+	 * @param targetMode
+	 *            Mode [Internal|External].
+	 * @param relationshipType
+	 *            Type of relationship.
+	 * @return The newly created and added relationship
+	 */
+	public abstract PackageRelationship addRelationship(
+			PackagePartName targetPartName, TargetMode targetMode,
+			String relationshipType);
+
+	/**
+	 * Add a relationship to a part (except relationships 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
+	 *            Name of the target part. This one must be relative to the
+	 *            source root directory of the part.
+	 * @param targetMode
+	 *            Mode [Internal|External].
+	 * @param relationshipType
+	 *            Type of relationship.
+	 * @param id
+	 *            Relationship unique id.
+	 * @return The newly created and added relationship
+	 * 
+	 * @throws InvalidFormatException
+	 *             If the URI point to a relationship part URI.
+	 */
+	public abstract PackageRelationship addRelationship(
+			PackagePartName targetPartName, TargetMode targetMode,
+			String relationshipType, String id);
+
+	/**
+	 * 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
+	 * @see org.apache.poi.openxml4j.opc.RelationshipSource#addExternalRelationship(java.lang.String, java.lang.String)
+	 */
+	public PackageRelationship addExternalRelationship(String target, String relationshipType);
+	
+	/**
+	 * 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 org.apache.poi.openxml4j.opc.RelationshipSource#addExternalRelationship(java.lang.String, java.lang.String)
+	 */
+	public PackageRelationship addExternalRelationship(String target, String relationshipType, String id);
+	
+	/**
+	 * Delete all the relationships attached to this.
+	 */
+	public abstract void clearRelationships();
+
+	/**
+	 * Delete the relationship specified by its id.
+	 * 
+	 * @param id
+	 *            The ID identified the part to delete.
+	 */
+	public abstract void removeRelationship(String id);
+
+	/**
+	 * Retrieve all the relationships attached to this.
+	 * 
+	 * @return This part's relationships.
+	 * @throws OpenXML4JException
+	 */
+	public abstract PackageRelationshipCollection getRelationships()
+			throws InvalidFormatException, OpenXML4JException;
+
+	/**
+	 * Retrieves a package relationship from its id.
+	 * 
+	 * @param id
+	 *            ID of the package relationship to retrieve.
+	 * @return The package relationship
+	 */
+	public abstract PackageRelationship getRelationship(String id);
+
+	/**
+	 * Retrieve all relationships attached to this part which have the specified
+	 * type.
+	 * 
+	 * @param relationshipType
+	 *            Relationship type filter.
+	 * @return All relationships from this part that have the specified type.
+	 * @throws InvalidFormatException
+	 *             If an error occurs while parsing the part.
+	 * @throws InvalidOperationException
+	 *             If the package is open in write only mode.
+	 */
+	public abstract PackageRelationshipCollection getRelationshipsByType(
+			String relationshipType) throws InvalidFormatException, 
+			IllegalArgumentException, OpenXML4JException;
+
+	/**
+	 * Knows if the part have any relationships.
+	 * 
+	 * @return <b>true</b> if the part have at least one relationship else
+	 *         <b>false</b>.
+	 */
+	public abstract boolean hasRelationships();
+
+	/**
+	 * Checks if the specified relationship is part of this package part.
+	 * 
+	 * @param rel
+	 *            The relationship to check.
+	 * @return <b>true</b> if the specified relationship exists in this part,
+	 *         else returns <b>false</b>
+	 */
+	@SuppressWarnings("finally")
+	public abstract boolean isRelationshipExists(PackageRelationship rel);
+
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/RelationshipSource.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/StreamHelper.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/StreamHelper.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/StreamHelper.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/StreamHelper.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,77 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.dom4j.Document;
+import org.dom4j.io.OutputFormat;
+import org.dom4j.io.XMLWriter;
+
+public final class StreamHelper {
+
+	private StreamHelper() {
+		// Do nothing
+	}
+
+	/**
+	 * Turning the DOM4j object in the specified output stream.
+	 * 
+	 * @param xmlContent
+	 *            The XML document.
+	 * @param outStream
+	 *            The OutputStream in which the XML document will be written.
+	 * @return <b>true</b> if the xml is successfully written in the stream,
+	 *         else <b>false</b>.
+	 */
+	public static boolean saveXmlInStream(Document xmlContent,
+			OutputStream outStream) {
+		try {
+			OutputFormat outformat = OutputFormat.createPrettyPrint();
+			outformat.setEncoding("UTF-8");
+			XMLWriter writer = new XMLWriter(outStream, outformat);
+			writer.write(xmlContent);
+		} catch (Exception e) {
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Copy the input stream into the output stream.
+	 * 
+	 * @param inStream
+	 *            The source stream.
+	 * @param outStream
+	 *            The destination stream.
+	 * @return <b>true</b> if the operation succeed, else return <b>false</b>.
+	 */
+	public static boolean copyStream(InputStream inStream, OutputStream outStream) {
+		try {
+			byte[] buffer = new byte[1024];
+			int bytesRead;
+			while ((bytesRead = inStream.read(buffer)) >= 0) {
+				outStream.write(buffer, 0, bytesRead);
+			}
+		} catch (Exception e) {
+			return false;
+		}
+		return true;
+	}
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/StreamHelper.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/TargetMode.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/TargetMode.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/TargetMode.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/TargetMode.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,32 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc;
+
+/**
+ * Specifies whether the target of a PackageRelationship is inside or outside a
+ * Package.
+ * 
+ * @author Julien Chable
+ * @version 1.0
+ */
+public enum TargetMode {
+	/** The relationship references a resource that is external to the package. */
+	INTERNAL,
+	/** The relationship references a part that is inside the package. */
+	EXTERNAL
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/TargetMode.java
------------------------------------------------------------------------------
    svn:executable = *



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