[bug-62522] include partName in exception message

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1835276 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
PJ Fanning 2018-07-06 19:07:22 +00:00
parent 0c3e972a71
commit 75d1771f49

View File

@ -43,433 +43,434 @@ import org.xml.sax.SAXException;
*/
public abstract class ContentTypeManager {
/**
* Content type part name.
*/
public static final String CONTENT_TYPES_PART_NAME = "[Content_Types].xml";
/**
* Content type part name.
*/
public static final String CONTENT_TYPES_PART_NAME = "[Content_Types].xml";
/**
* Content type namespace
*/
public static final String TYPES_NAMESPACE_URI = PackageNamespaces.CONTENT_TYPES;
/**
* Content type namespace
*/
public static final String TYPES_NAMESPACE_URI = PackageNamespaces.CONTENT_TYPES;
/* Xml elements in content type part */
/* Xml elements in content type part */
private static final String TYPES_TAG_NAME = "Types";
private static final String TYPES_TAG_NAME = "Types";
private static final String DEFAULT_TAG_NAME = "Default";
private static final String DEFAULT_TAG_NAME = "Default";
private static final String EXTENSION_ATTRIBUTE_NAME = "Extension";
private static final String EXTENSION_ATTRIBUTE_NAME = "Extension";
private static final String CONTENT_TYPE_ATTRIBUTE_NAME = "ContentType";
private static final String CONTENT_TYPE_ATTRIBUTE_NAME = "ContentType";
private static final String OVERRIDE_TAG_NAME = "Override";
private static final String OVERRIDE_TAG_NAME = "Override";
private static final String PART_NAME_ATTRIBUTE_NAME = "PartName";
private static final String PART_NAME_ATTRIBUTE_NAME = "PartName";
/**
* Reference to the package using this content type manager.
*/
protected OPCPackage container;
/**
* Reference to the package using this content type manager.
*/
protected OPCPackage container;
/**
* Default content type tree. <Extension, ContentType>
*/
private TreeMap<String, String> defaultContentType;
/**
* Default content type tree. <Extension, ContentType>
*/
private TreeMap<String, String> defaultContentType;
/**
* Override content type tree.
*/
private TreeMap<PackagePartName, String> overrideContentType;
/**
* Override content type tree.
*/
private TreeMap<PackagePartName, String> overrideContentType;
/**
* Constructor. Parses the content of the specified input stream.
*
* @param in
* If different of <i>null</i> then the content types part is
* retrieve and parse.
* @throws InvalidFormatException
* If the content types part content is not valid.
*/
public ContentTypeManager(InputStream in, OPCPackage pkg)
throws InvalidFormatException {
this.container = pkg;
this.defaultContentType = new TreeMap<>();
if (in != null) {
try {
parseContentTypesFile(in);
} catch (InvalidFormatException e) {
InvalidFormatException ex = new InvalidFormatException("Can't read content types part !");
/**
* Constructor. Parses the content of the specified input stream.
*
* @param in
* If different of <i>null</i> then the content types part is
* retrieve and parse.
* @throws InvalidFormatException
* If the content types part content is not valid.
*/
public ContentTypeManager(InputStream in, OPCPackage pkg)
throws InvalidFormatException {
this.container = pkg;
this.defaultContentType = new TreeMap<>();
if (in != null) {
try {
parseContentTypesFile(in);
} catch (InvalidFormatException e) {
InvalidFormatException ex = new InvalidFormatException("Can't read content types part !");
// here it is useful to add the cause to not loose the original stack-trace
ex.initCause(e);
throw ex;
}
}
}
}
}
}
/**
* Build association extention-> content type (will be stored in
* [Content_Types].xml) for example ContentType="image/png" Extension="png"
* <p>
* [M2.8]: When adding a new part to a package, the package implementer
* shall ensure that a content type for that part is specified in the
* Content Types stream; the package implementer shall perform the steps
* described in &#167;9.1.2.3:
* </p><p>
* 1. Get the extension from the part name by taking the substring to the
* right of the rightmost occurrence of the dot character (.) from the
* rightmost segment.
* </p><p>
* 2. If a part name has no extension, a corresponding Override element
* shall be added to the Content Types stream.
* </p><p>
* 3. Compare the resulting extension with the values specified for the
* Extension attributes of the Default elements in the Content Types stream.
* The comparison shall be case-insensitive ASCII.
* </p><p>
* 4. If there is a Default element with a matching Extension attribute,
* then the content type of the new part shall be compared with the value of
* the ContentType attribute. The comparison might be case-sensitive and
* include every character regardless of the role it plays in the
* content-type grammar of RFC 2616, or it might follow the grammar of RFC
* 2616.
* </p><p>
* a. If the content types match, no further action is required.
* </p><p>
* b. If the content types do not match, a new Override element shall be
* added to the Content Types stream. .
* </p><p>
* 5. If there is no Default element with a matching Extension attribute, a
* new Default element or Override element shall be added to the Content
* Types stream.
* </p>
*/
public void addContentType(PackagePartName partName, String contentType) {
boolean defaultCTExists = this.defaultContentType.containsValue(contentType);
String extension = partName.getExtension().toLowerCase(Locale.ROOT);
if ((extension.length() == 0)
|| (this.defaultContentType.containsKey(extension) && !defaultCTExists))
this.addOverrideContentType(partName, contentType);
else if (!defaultCTExists)
this.addDefaultContentType(extension, contentType);
}
/**
* Add an override content type for a specific part.
*
* @param partName
* Name of the part.
* @param contentType
* Content type of the part.
*/
private void addOverrideContentType(PackagePartName partName,
String contentType) {
if (overrideContentType == null)
overrideContentType = new TreeMap<>();
overrideContentType.put(partName, contentType);
}
/**
* Add a content type associated with the specified extension.
*
* @param extension
* The part name extension to bind to a content type.
* @param contentType
* The content type associated with the specified extension.
*/
private void addDefaultContentType(String extension, String contentType) {
// Remark : Originally the latest parameter was :
// contentType.toLowerCase(). Change due to a request ID 1996748.
defaultContentType.put(extension.toLowerCase(Locale.ROOT), contentType);
}
/**
/**
* Build association extention-> content type (will be stored in
* [Content_Types].xml) for example ContentType="image/png" Extension="png"
* <p>
* Delete a content type based on the specified part name. If the specified
* part name is register with an override content type, then this content
* type is remove, else the content type is remove in the default content
* type list if it exists and if no part is associated with it yet.
* </p><p>
* Check rule M2.4: The package implementer shall require that the Content
* Types stream contain one of the following for every part in the package:
* One matching Default element One matching Override element Both a
* matching Default element and a matching Override element, in which case
* the Override element takes precedence.
* </p>
* @param partName
* The part URI associated with the override content type to
* delete.
* @exception InvalidOperationException
* Throws if
*/
public void removeContentType(PackagePartName partName)
throws InvalidOperationException {
if (partName == null)
throw new IllegalArgumentException("partName");
* [M2.8]: When adding a new part to a package, the package implementer
* shall ensure that a content type for that part is specified in the
* Content Types stream; the package implementer shall perform the steps
* described in &#167;9.1.2.3:
* </p><p>
* 1. Get the extension from the part name by taking the substring to the
* right of the rightmost occurrence of the dot character (.) from the
* rightmost segment.
* </p><p>
* 2. If a part name has no extension, a corresponding Override element
* shall be added to the Content Types stream.
* </p><p>
* 3. Compare the resulting extension with the values specified for the
* Extension attributes of the Default elements in the Content Types stream.
* The comparison shall be case-insensitive ASCII.
* </p><p>
* 4. If there is a Default element with a matching Extension attribute,
* then the content type of the new part shall be compared with the value of
* the ContentType attribute. The comparison might be case-sensitive and
* include every character regardless of the role it plays in the
* content-type grammar of RFC 2616, or it might follow the grammar of RFC
* 2616.
* </p><p>
* a. If the content types match, no further action is required.
* </p><p>
* b. If the content types do not match, a new Override element shall be
* added to the Content Types stream. .
* </p><p>
* 5. If there is no Default element with a matching Extension attribute, a
* new Default element or Override element shall be added to the Content
* Types stream.
* </p>
*/
public void addContentType(PackagePartName partName, String contentType) {
boolean defaultCTExists = this.defaultContentType.containsValue(contentType);
String extension = partName.getExtension().toLowerCase(Locale.ROOT);
if ((extension.length() == 0)
|| (this.defaultContentType.containsKey(extension) && !defaultCTExists))
this.addOverrideContentType(partName, contentType);
else if (!defaultCTExists)
this.addDefaultContentType(extension, contentType);
}
/* Override content type */
if (this.overrideContentType != null
&& (this.overrideContentType.get(partName) != null)) {
// Remove the override definition for the specified part.
this.overrideContentType.remove(partName);
return;
}
/**
* Add an override content type for a specific part.
*
* @param partName
* Name of the part.
* @param contentType
* Content type of the part.
*/
private void addOverrideContentType(PackagePartName partName,
String contentType) {
if (overrideContentType == null)
overrideContentType = new TreeMap<>();
overrideContentType.put(partName, contentType);
}
/* Default content type */
String extensionToDelete = partName.getExtension();
boolean deleteDefaultContentTypeFlag = true;
if (this.container != null) {
try {
for (PackagePart part : this.container.getParts()) {
if (!part.getPartName().equals(partName)
&& part.getPartName().getExtension()
.equalsIgnoreCase(extensionToDelete)) {
deleteDefaultContentTypeFlag = false;
break;
}
}
} catch (InvalidFormatException e) {
throw new InvalidOperationException(e.getMessage());
}
}
/**
* Add a content type associated with the specified extension.
*
* @param extension
* The part name extension to bind to a content type.
* @param contentType
* The content type associated with the specified extension.
*/
private void addDefaultContentType(String extension, String contentType) {
// Remark : Originally the latest parameter was :
// contentType.toLowerCase(). Change due to a request ID 1996748.
defaultContentType.put(extension.toLowerCase(Locale.ROOT), contentType);
}
// Remove the default content type, no other part use this content type.
if (deleteDefaultContentTypeFlag) {
this.defaultContentType.remove(extensionToDelete);
}
/**
* <p>
* Delete a content type based on the specified part name. If the specified
* part name is register with an override content type, then this content
* type is remove, else the content type is remove in the default content
* type list if it exists and if no part is associated with it yet.
* </p><p>
* Check rule M2.4: The package implementer shall require that the Content
* Types stream contain one of the following for every part in the package:
* One matching Default element One matching Override element Both a
* matching Default element and a matching Override element, in which case
* the Override element takes precedence.
* </p>
* @param partName
* The part URI associated with the override content type to
* delete.
* @exception InvalidOperationException
* Throws if
*/
public void removeContentType(PackagePartName partName)
throws InvalidOperationException {
if (partName == null)
throw new IllegalArgumentException("partName");
/*
* Check rule 2.4: The package implementer shall require that the
* Content Types stream contain one of the following for every part in
* the package: One matching Default element One matching Override
* element Both a matching Default element and a matching Override
* element, in which case the Override element takes precedence.
*/
if (this.container != null) {
try {
for (PackagePart part : this.container.getParts()) {
if (!part.getPartName().equals(partName)
&& this.getContentType(part.getPartName()) == null)
throw new InvalidOperationException(
"Rule M2.4 is not respected: Nor a default element or override element is associated with the part: "
+ part.getPartName().getName());
}
} catch (InvalidFormatException e) {
throw new InvalidOperationException(e.getMessage());
}
}
}
/* Override content type */
if (this.overrideContentType != null
&& (this.overrideContentType.get(partName) != null)) {
// Remove the override definition for the specified part.
this.overrideContentType.remove(partName);
return;
}
/**
* Check if the specified content type is already register.
*
* @param contentType
* The content type to check.
* @return <code>true</code> if the specified content type is already
* register, then <code>false</code>.
*/
public boolean isContentTypeRegister(String contentType) {
if (contentType == null)
throw new IllegalArgumentException("contentType");
/* Default content type */
String extensionToDelete = partName.getExtension();
boolean deleteDefaultContentTypeFlag = true;
if (this.container != null) {
try {
for (PackagePart part : this.container.getParts()) {
if (!part.getPartName().equals(partName)
&& part.getPartName().getExtension()
.equalsIgnoreCase(extensionToDelete)) {
deleteDefaultContentTypeFlag = false;
break;
}
}
} catch (InvalidFormatException e) {
throw new InvalidOperationException(e.getMessage());
}
}
return (this.defaultContentType.values().contains(contentType) || (this.overrideContentType != null && this.overrideContentType
.values().contains(contentType)));
}
// Remove the default content type, no other part use this content type.
if (deleteDefaultContentTypeFlag) {
this.defaultContentType.remove(extensionToDelete);
}
/**
* Get the content type for the specified part, if any.
* <p>
* Rule [M2.9]: To get the content type of a part, the package implementer
* shall perform the steps described in &#167;9.1.2.4:
* </p><p>
* 1. Compare the part name with the values specified for the PartName
* attribute of the Override elements. The comparison shall be
* case-insensitive ASCII.
* </p><p>
* 2. If there is an Override element with a matching PartName attribute,
* return the value of its ContentType attribute. No further action is
* required.
* </p><p>
* 3. If there is no Override element with a matching PartName attribute,
* then a. Get the extension from the part name by taking the substring to
* the right of the rightmost occurrence of the dot character (.) from the
* rightmost segment. b. Check the Default elements of the Content Types
* stream, comparing the extension with the value of the Extension
* attribute. The comparison shall be case-insensitive ASCII.
* </p><p>
* 4. If there is a Default element with a matching Extension attribute,
* return the value of its ContentType attribute. No further action is
* required.
* </p><p>
* 5. If neither Override nor Default elements with matching attributes are
* found for the specified part name, the implementation shall not map this
* part name to a part.
* </p>
* @param partName
* The URI part to check.
* @return The content type associated with the URI (in case of an override
* content type) or the extension (in case of default content type),
* else <code>null</code>.
*
* @exception OpenXML4JRuntimeException
* Throws if the content type manager is not able to find the
* content from an existing part.
*/
public String getContentType(PackagePartName partName) {
if (partName == null)
throw new IllegalArgumentException("partName");
/*
* Check rule 2.4: The package implementer shall require that the
* Content Types stream contain one of the following for every part in
* the package: One matching Default element One matching Override
* element Both a matching Default element and a matching Override
* element, in which case the Override element takes precedence.
*/
if (this.container != null) {
try {
for (PackagePart part : this.container.getParts()) {
if (!part.getPartName().equals(partName)
&& this.getContentType(part.getPartName()) == null)
throw new InvalidOperationException(
"Rule M2.4 is not respected: Nor a default element or override element is associated with the part: "
+ part.getPartName().getName());
}
} catch (InvalidFormatException e) {
throw new InvalidOperationException(e.getMessage());
}
}
}
if ((this.overrideContentType != null)
&& this.overrideContentType.containsKey(partName))
return this.overrideContentType.get(partName);
/**
* Check if the specified content type is already register.
*
* @param contentType
* The content type to check.
* @return <code>true</code> if the specified content type is already
* register, then <code>false</code>.
*/
public boolean isContentTypeRegister(String contentType) {
if (contentType == null)
throw new IllegalArgumentException("contentType");
String extension = partName.getExtension().toLowerCase(Locale.ROOT);
if (this.defaultContentType.containsKey(extension))
return this.defaultContentType.get(extension);
return (this.defaultContentType.values().contains(contentType) || (this.overrideContentType != null && this.overrideContentType
.values().contains(contentType)));
}
/*
* [M2.4] : The package implementer shall require that the Content Types
* stream contain one of the following for every part in the package:
* One matching Default element, One matching Override element, Both a
* matching Default element and a matching Override element, in which
* case the Override element takes precedence.
*/
if (this.container != null && this.container.getPart(partName) != null) {
throw new OpenXML4JRuntimeException(
"Rule M2.4 exception : this error should NEVER happen! If you can provide the triggering file, then please raise a bug at https://bz.apache.org/bugzilla/enter_bug.cgi?product=POI and attach the file that triggers it, thanks!");
}
return null;
}
/**
* Get the content type for the specified part, if any.
* <p>
* Rule [M2.9]: To get the content type of a part, the package implementer
* shall perform the steps described in &#167;9.1.2.4:
* </p><p>
* 1. Compare the part name with the values specified for the PartName
* attribute of the Override elements. The comparison shall be
* case-insensitive ASCII.
* </p><p>
* 2. If there is an Override element with a matching PartName attribute,
* return the value of its ContentType attribute. No further action is
* required.
* </p><p>
* 3. If there is no Override element with a matching PartName attribute,
* then a. Get the extension from the part name by taking the substring to
* the right of the rightmost occurrence of the dot character (.) from the
* rightmost segment. b. Check the Default elements of the Content Types
* stream, comparing the extension with the value of the Extension
* attribute. The comparison shall be case-insensitive ASCII.
* </p><p>
* 4. If there is a Default element with a matching Extension attribute,
* return the value of its ContentType attribute. No further action is
* required.
* </p><p>
* 5. If neither Override nor Default elements with matching attributes are
* found for the specified part name, the implementation shall not map this
* part name to a part.
* </p>
* @param partName
* The URI part to check.
* @return The content type associated with the URI (in case of an override
* content type) or the extension (in case of default content type),
* else <code>null</code>.
*
* @exception OpenXML4JRuntimeException
* Throws if the content type manager is not able to find the
* content from an existing part.
*/
public String getContentType(PackagePartName partName) {
if (partName == null)
throw new IllegalArgumentException("partName");
/**
* Clear all content types.
*/
public void clearAll() {
this.defaultContentType.clear();
if (this.overrideContentType != null)
this.overrideContentType.clear();
}
if ((this.overrideContentType != null)
&& this.overrideContentType.containsKey(partName))
return this.overrideContentType.get(partName);
/**
* Clear all override content types.
*
*/
public void clearOverrideContentTypes() {
if (this.overrideContentType != null)
this.overrideContentType.clear();
}
String extension = partName.getExtension().toLowerCase(Locale.ROOT);
if (this.defaultContentType.containsKey(extension))
return this.defaultContentType.get(extension);
/**
* Parse the content types part.
*
* @throws InvalidFormatException
* Throws if the content type doesn't exist or the XML format is
* invalid.
*/
private void parseContentTypesFile(InputStream in)
throws InvalidFormatException {
try {
Document xmlContentTypetDoc = DocumentHelper.readDocument(in);
/*
* [M2.4] : The package implementer shall require that the Content Types
* stream contain one of the following for every part in the package:
* One matching Default element, One matching Override element, Both a
* matching Default element and a matching Override element, in which
* case the Override element takes precedence.
*/
if (this.container != null && this.container.getPart(partName) != null) {
throw new OpenXML4JRuntimeException(
"Rule M2.4 exception : Part \'" + partName +
"\' not found - this error should NEVER happen! If you can provide the triggering file, then please raise a bug at https://bz.apache.org/bugzilla/enter_bug.cgi?product=POI and attach the file that triggers it, thanks!");
}
return null;
}
// Default content types
NodeList defaultTypes = xmlContentTypetDoc.getDocumentElement().getElementsByTagNameNS(TYPES_NAMESPACE_URI, DEFAULT_TAG_NAME);
int defaultTypeCount = defaultTypes.getLength();
for (int i = 0; i < defaultTypeCount; i++) {
/**
* Clear all content types.
*/
public void clearAll() {
this.defaultContentType.clear();
if (this.overrideContentType != null)
this.overrideContentType.clear();
}
/**
* Clear all override content types.
*
*/
public void clearOverrideContentTypes() {
if (this.overrideContentType != null)
this.overrideContentType.clear();
}
/**
* Parse the content types part.
*
* @throws InvalidFormatException
* Throws if the content type doesn't exist or the XML format is
* invalid.
*/
private void parseContentTypesFile(InputStream in)
throws InvalidFormatException {
try {
Document xmlContentTypetDoc = DocumentHelper.readDocument(in);
// Default content types
NodeList defaultTypes = xmlContentTypetDoc.getDocumentElement().getElementsByTagNameNS(TYPES_NAMESPACE_URI, DEFAULT_TAG_NAME);
int defaultTypeCount = defaultTypes.getLength();
for (int i = 0; i < defaultTypeCount; i++) {
Element element = (Element) defaultTypes.item(i);
String extension = element.getAttribute(EXTENSION_ATTRIBUTE_NAME);
String contentType = element.getAttribute(CONTENT_TYPE_ATTRIBUTE_NAME);
addDefaultContentType(extension, contentType);
}
String extension = element.getAttribute(EXTENSION_ATTRIBUTE_NAME);
String contentType = element.getAttribute(CONTENT_TYPE_ATTRIBUTE_NAME);
addDefaultContentType(extension, contentType);
}
// Overriden content types
// Overriden content types
NodeList overrideTypes = xmlContentTypetDoc.getDocumentElement().getElementsByTagNameNS(TYPES_NAMESPACE_URI, OVERRIDE_TAG_NAME);
int overrideTypeCount = overrideTypes.getLength();
for (int i = 0; i < overrideTypeCount; i++) {
Element element = (Element) overrideTypes.item(i);
URI uri = new URI(element.getAttribute(PART_NAME_ATTRIBUTE_NAME));
PackagePartName partName = PackagingURIHelper.createPartName(uri);
String contentType = element.getAttribute(CONTENT_TYPE_ATTRIBUTE_NAME);
addOverrideContentType(partName, contentType);
}
} catch (URISyntaxException | IOException | SAXException e) {
throw new InvalidFormatException(e.getMessage());
Element element = (Element) overrideTypes.item(i);
URI uri = new URI(element.getAttribute(PART_NAME_ATTRIBUTE_NAME));
PackagePartName partName = PackagingURIHelper.createPartName(uri);
String contentType = element.getAttribute(CONTENT_TYPE_ATTRIBUTE_NAME);
addOverrideContentType(partName, contentType);
}
} catch (URISyntaxException | IOException | SAXException e) {
throw new InvalidFormatException(e.getMessage());
}
}
}
/**
* Save the contents type part.
*
* @param outStream
* The output stream use to save the XML content of the content
* types part.
* @return <b>true</b> if the operation success, else <b>false</b>.
*/
public boolean save(OutputStream outStream) {
Document xmlOutDoc = DocumentHelper.createDocument();
/**
* Save the contents type part.
*
* @param outStream
* The output stream use to save the XML content of the content
* types part.
* @return <b>true</b> if the operation success, else <b>false</b>.
*/
public boolean save(OutputStream outStream) {
Document xmlOutDoc = DocumentHelper.createDocument();
// Building namespace
Element typesElem = xmlOutDoc.createElementNS(TYPES_NAMESPACE_URI, TYPES_TAG_NAME);
// Building namespace
Element typesElem = xmlOutDoc.createElementNS(TYPES_NAMESPACE_URI, TYPES_TAG_NAME);
xmlOutDoc.appendChild(typesElem);
// Adding default types
for (Entry<String, String> entry : defaultContentType.entrySet()) {
appendDefaultType(typesElem, entry);
}
// Adding default types
for (Entry<String, String> entry : defaultContentType.entrySet()) {
appendDefaultType(typesElem, entry);
}
// Adding specific types if any exist
if (overrideContentType != null) {
for (Entry<PackagePartName, String> entry : overrideContentType
.entrySet()) {
appendSpecificTypes(typesElem, entry);
}
}
xmlOutDoc.normalize();
// Adding specific types if any exist
if (overrideContentType != null) {
for (Entry<PackagePartName, String> entry : overrideContentType
.entrySet()) {
appendSpecificTypes(typesElem, entry);
}
}
xmlOutDoc.normalize();
// Save content in the specified output stream
return this.saveImpl(xmlOutDoc, outStream);
}
// Save content in the specified output stream
return this.saveImpl(xmlOutDoc, outStream);
}
/**
* Use to append specific type XML elements, use by the save() method.
*
* @param root
* XML parent element use to append this override type element.
* @param entry
* The values to append.
* @see #save(java.io.OutputStream)
*/
private void appendSpecificTypes(Element root,
Entry<PackagePartName, String> entry) {
/**
* Use to append specific type XML elements, use by the save() method.
*
* @param root
* XML parent element use to append this override type element.
* @param entry
* The values to append.
* @see #save(java.io.OutputStream)
*/
private void appendSpecificTypes(Element root,
Entry<PackagePartName, String> entry) {
Element specificType = root.getOwnerDocument().createElementNS(TYPES_NAMESPACE_URI, OVERRIDE_TAG_NAME);
specificType.setAttribute(PART_NAME_ATTRIBUTE_NAME, entry.getKey().getName());
specificType.setAttribute(CONTENT_TYPE_ATTRIBUTE_NAME, entry.getValue());
root.appendChild(specificType);
}
}
/**
* Use to append default types XML elements, use by the save() method.
*
* @param root
* XML parent element use to append this default type element.
* @param entry
* The values to append.
* @see #save(java.io.OutputStream)
*/
private void appendDefaultType(Element root, Entry<String, String> entry) {
/**
* Use to append default types XML elements, use by the save() method.
*
* @param root
* XML parent element use to append this default type element.
* @param entry
* The values to append.
* @see #save(java.io.OutputStream)
*/
private void appendDefaultType(Element root, Entry<String, String> entry) {
Element defaultType = root.getOwnerDocument().createElementNS(TYPES_NAMESPACE_URI, DEFAULT_TAG_NAME);
defaultType.setAttribute(EXTENSION_ATTRIBUTE_NAME, entry.getKey());
defaultType.setAttribute(CONTENT_TYPE_ATTRIBUTE_NAME, entry.getValue());
root.appendChild(defaultType);
}
}
/**
* Specific implementation of the save method. Call by the save() method,
* call before exiting.
*
* @param out
* The output stream use to write the content type XML.
*/
public abstract boolean saveImpl(Document content, OutputStream out);
/**
* Specific implementation of the save method. Call by the save() method,
* call before exiting.
*
* @param out
* The output stream use to write the content type XML.
*/
public abstract boolean saveImpl(Document content, OutputStream out);
}