org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of apache-poi-ooxml Show documentation
Show all versions of apache-poi-ooxml Show documentation
The Apache Commons Codec package contains simple encoder and decoders for
various formats such as Base64 and Hexadecimal. In addition to these
widely used encoders and decoders, the codec package also maintains a
collection of phonetic encoding utilities.
/* ====================================================================
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.internal;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
import org.apache.poi.openxml4j.opc.ContentTypes;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageNamespaces;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageProperties;
import org.apache.poi.util.LocaleUtil;
/**
* Represents the core properties part of a package.
*/
public final class PackagePropertiesPart extends PackagePart implements PackageProperties {
public static final String NAMESPACE_DC_URI = PackageProperties.NAMESPACE_DC;
public static final String NAMESPACE_CP_URI = PackageNamespaces.CORE_PROPERTIES;
public static final String NAMESPACE_DCTERMS_URI = PackageProperties.NAMESPACE_DCTERMS;
private static final String DEFAULT_DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private static final String[] DATE_FORMATS = new String[]{
DEFAULT_DATEFORMAT,
"yyyy-MM-dd'T'HH:mm:ss.SS'Z'",
"yyyy-MM-dd"
};
//Had to add this and TIME_ZONE_PAT to handle tz with colons.
//When we move to Java 7, we should be able to add another
//date format to DATE_FORMATS that uses XXX and get rid of this
//and TIME_ZONE_PAT
// TODO Fix this after the Java 7 upgrade
private final String[] TZ_DATE_FORMATS = new String[]{
"yyyy-MM-dd'T'HH:mm:ssz",
"yyyy-MM-dd'T'HH:mm:ss.Sz",
"yyyy-MM-dd'T'HH:mm:ss.SSz",
"yyyy-MM-dd'T'HH:mm:ss.SSSz",
};
private final Pattern TIME_ZONE_PAT = Pattern.compile("([-+]\\d\\d):?(\\d\\d)");
/**
* Constructor.
*
* @param pack
* Container package.
* @param partName
* Name of this part.
* @throws InvalidFormatException
* Throws if the content is invalid.
*/
public PackagePropertiesPart(OPCPackage pack, PackagePartName partName)
throws InvalidFormatException {
super(pack, partName, ContentTypes.CORE_PROPERTIES_PART);
}
/**
* A categorization of the content of this package.
*
* [Example: Example values for this property might include: Resume, Letter,
* Financial Forecast, Proposal, Technical Presentation, and so on. This
* value might be used by an application's user interface to facilitate
* navigation of a large set of documents. end example]
*/
protected Optional category = Optional.empty();
/**
* The status of the content.
*
* [Example: Values might include "Draft", "Reviewed", and "Final". end
* example]
*/
protected Optional contentStatus = Optional.empty();
/**
* The type of content represented, generally defined by a specific use and
* intended audience.
*
* [Example: Values might include "Whitepaper", "Security Bulletin", and
* "Exam". end example] [Note: This property is distinct from MIME content
* types as defined in RFC 2616. end note]
*/
protected Optional contentType = Optional.empty();
/**
* Date of creation of the resource.
*/
protected Optional created = Optional.empty();
/**
* An entity primarily responsible for making the content of the resource.
*/
protected Optional creator = Optional.empty();
/**
* An explanation of the content of the resource.
*
* [Example: Values might include an abstract, table of contents, reference
* to a graphical representation of content, and a free-text account of the
* content. end example]
*/
protected Optional description = Optional.empty();
/**
* An unambiguous reference to the resource within a given context.
*/
protected Optional identifier = Optional.empty();
/**
* 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.
*/
protected Optional keywords = Optional.empty();
/**
* The language of the intellectual content of the resource.
*
* [Note: IETF RFC 3066 provides guidance on encoding to represent
* languages. end note]
*/
protected Optional language = Optional.empty();
/**
* The user who performed the last modification. The identification is
* environment-specific.
*
* [Example: A name, email address, or employee ID. end example] It is
* recommended that this value be as concise as possible.
*/
protected Optional lastModifiedBy = Optional.empty();
/**
* The date and time of the last printing.
*/
protected Optional lastPrinted = Optional.empty();
/**
* Date on which the resource was changed.
*/
protected Optional modified = Optional.empty();
/**
* The revision number.
*
* [Example: This value might indicate the number of saves or revisions,
* provided the application updates it after each revision. end example]
*/
protected Optional revision = Optional.empty();
/**
* The topic of the content of the resource.
*/
protected Optional subject = Optional.empty();
/**
* The name given to the resource.
*/
protected Optional title = Optional.empty();
/**
* The version number. This value is set by the user or by the application.
*/
protected Optional version = Optional.empty();
/*
* Getters and setters
*/
/**
* Get the category property.
*
*/
@Override
public Optional getCategoryProperty() {
return category;
}
/**
* Get content status.
*
*/
@Override
public Optional getContentStatusProperty() {
return contentStatus;
}
/**
* Get content type.
*
*/
@Override
public Optional getContentTypeProperty() {
return contentType;
}
/**
* Get created date.
*
*/
@Override
public Optional getCreatedProperty() {
return created;
}
/**
* Get created date formatted into a String.
*
* @return A string representation of the created date.
*/
public String getCreatedPropertyString() {
return getDateValue(created);
}
/**
* Get creator.
*
*/
@Override
public Optional getCreatorProperty() {
return creator;
}
/**
* Get description.
*
*/
@Override
public Optional getDescriptionProperty() {
return description;
}
/**
* Get identifier.
*
*/
@Override
public Optional getIdentifierProperty() {
return identifier;
}
/**
* Get keywords.
*
*/
@Override
public Optional getKeywordsProperty() {
return keywords;
}
/**
* Get the language.
*
*/
@Override
public Optional getLanguageProperty() {
return language;
}
/**
* Get the author of last modifications.
*
*/
@Override
public Optional getLastModifiedByProperty() {
return lastModifiedBy;
}
/**
* Get last printed date.
*
*/
@Override
public Optional getLastPrintedProperty() {
return lastPrinted;
}
/**
* Get last printed date formatted into a String.
*
* @return A string representation of the last printed date.
*/
public String getLastPrintedPropertyString() {
return getDateValue(lastPrinted);
}
/**
* Get modified date.
*
*/
@Override
public Optional getModifiedProperty() {
return modified;
}
/**
* Get modified date formatted into a String.
*
* @return A string representation of the modified date.
*/
public String getModifiedPropertyString() {
if (modified.isPresent()) {
return getDateValue(modified);
}
return getDateValue(Optional.of(new Date()));
}
/**
* Get revision.
*
*/
@Override
public Optional getRevisionProperty() {
return revision;
}
/**
* Get subject.
*
*/
@Override
public Optional getSubjectProperty() {
return subject;
}
/**
* Get title.
*
*/
@Override
public Optional getTitleProperty() {
return title;
}
/**
* Get version.
*
*/
@Override
public Optional getVersionProperty() {
return version;
}
/**
* Set the category.
*
*/
@Override
public void setCategoryProperty(String category) {
this.category = parseStringValue(category);
}
/**
* Set the category.
*
*/
@Override
public void setCategoryProperty(Optional category) { this.category = category; }
/**
* Set the content status.
*
*/
@Override
public void setContentStatusProperty(String contentStatus) {
this.contentStatus = parseStringValue(contentStatus);
}
/**
* Set the content status.
*
*/
@Override
public void setContentStatusProperty(Optional contentStatus) { this.contentStatus = contentStatus; }
/**
* Set the content type.
*
*/
@Override
public void setContentTypeProperty(String contentType) {
this.contentType = parseStringValue(contentType);
}
/**
* Set the content type.
*
*/
@Override
public void setContentTypeProperty(Optional contentType) { this.contentType = contentType; }
/**
* Set the created date.
*
* @see org.apache.poi.openxml4j.opc.PackageProperties#setCreatedProperty(java.util.Optional)
*/
@Override
public void setCreatedProperty(String created) throws InvalidFormatException {
this.created = parseDateValue(created);
}
/**
* Set the created date.
*
*/
@Override
public void setCreatedProperty(Optional created) {
this.created = created;
}
/**
* Set the creator.
*
*/
@Override
public void setCreatorProperty(String creator) {
this.creator = parseStringValue(creator);
}
/**
* Set the creator.
*
*/
@Override
public void setCreatorProperty(Optional creator) { this.creator = creator; }
/**
* Set the description.
*
*/
@Override
public void setDescriptionProperty(String description) {
this.description = parseStringValue(description);
}
/**
* Set the description.
*
*/
@Override
public void setDescriptionProperty(Optional description) { this.description = description; }
/**
* Set identifier.
*
*/
@Override
public void setIdentifierProperty(String identifier) {
this.identifier = parseStringValue(identifier);
}
/**
* Set identifier.
*
*/
@Override
public void setIdentifierProperty(Optional identifier) { this.identifier = identifier; }
/**
* Set keywords.
*
*/
@Override
public void setKeywordsProperty(String keywords) {
this.keywords = parseStringValue(keywords);
}
/**
* Set keywords.
*
*/
@Override
public void setKeywordsProperty(Optional keywords) { this.keywords = keywords; }
/**
* Set language.
*
*/
@Override
public void setLanguageProperty(String language) {
this.language = parseStringValue(language);
}
/**
* Set language.
*
*/
@Override
public void setLanguageProperty(Optional language) { this.language = language; }
/**
* Set last modifications author.
*
*/
@Override
public void setLastModifiedByProperty(String lastModifiedBy) {
this.lastModifiedBy = parseStringValue(lastModifiedBy);
}
/**
* Set last modifications author.
*
*/
@Override
public void setLastModifiedByProperty(Optional lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}
/**
* Set last printed date.
*
* @see org.apache.poi.openxml4j.opc.PackageProperties#setLastPrintedProperty(java.util.Optional)
*/
@Override
public void setLastPrintedProperty(String lastPrinted) throws InvalidFormatException {
this.lastPrinted = parseDateValue(lastPrinted);
}
/**
* Set last printed date.
*
*/
@Override
public void setLastPrintedProperty(Optional lastPrinted) {
this.lastPrinted = lastPrinted;
}
/**
* Set last modification date.
*
* @see org.apache.poi.openxml4j.opc.PackageProperties#setModifiedProperty(java.util.Optional)
*/
@Override
public void setModifiedProperty(String modified) throws InvalidFormatException {
this.modified = parseDateValue(modified);
}
/**
* Set last modification date.
*
*/
@Override
public void setModifiedProperty(Optional modified) {
this.modified = modified;
}
/**
* Set revision.
*
*/
@Override
public void setRevisionProperty(Optional revision) { this.revision = revision; }
/**
* Set revision.
*
*/
@Override
public void setRevisionProperty(String revision) {
this.revision = parseStringValue(revision);
}
/**
* Set subject.
*
*/
@Override
public void setSubjectProperty(String subject) {
this.subject = parseStringValue(subject);
}
/**
* Set subject.
*
*/
@Override
public void setSubjectProperty(Optional subject) { this.subject = subject; }
/**
* Set title.
*
*/
@Override
public void setTitleProperty(String title) {
this.title = parseStringValue(title);
}
/**
* Set title.
*
*/
@Override
public void setTitleProperty(Optional title) { this.title = title; }
/**
* Set version.
*
*/
@Override
public void setVersionProperty(String version) {
this.version = parseStringValue(version);
}
/**
* Set version.
*
*/
@Override
public void setVersionProperty(Optional version) { this.version = version; }
/**
* Convert a string value into a {@code Optional}
*/
private Optional parseStringValue(String s) {
if (s == null || s.isEmpty()) {
return Optional.empty();
}
return Optional.of(s);
}
/**
* Convert a string value represented a date into a {@code Optional}
*
* @throws InvalidFormatException
* Throws if the date format is not valid.
*/
private Optional parseDateValue(String dateStr) throws InvalidFormatException {
if (dateStr == null || dateStr.isEmpty()) {
return Optional.empty();
}
Matcher m = TIME_ZONE_PAT.matcher(dateStr);
Date d = null;
if (m.find()) {
String dateTzStr = dateStr.substring(0, m.start())+m.group(1)+m.group(2);
d = parseDateFormat(TZ_DATE_FORMATS, dateTzStr);
}
if (d == null) {
String dateTzStr = dateStr.endsWith("Z") ? dateStr : (dateStr + "Z");
d = parseDateFormat(DATE_FORMATS, dateTzStr);
}
if (d != null) {
return Optional.of(d);
}
//if you're here, no pattern matched, throw exception
String allFormats = Stream.of(TZ_DATE_FORMATS, DATE_FORMATS)
.flatMap(Stream::of).collect(Collectors.joining(", "));
throw new InvalidFormatException("Date " + dateStr + " not well formatted, expected format in: "+ allFormats);
}
private static Date parseDateFormat(String[] formats, String dateTzStr) {
for (String fStr : formats) {
SimpleDateFormat df = new SimpleDateFormat(fStr, Locale.ROOT);
df.setTimeZone(LocaleUtil.TIMEZONE_UTC);
Date d = df.parse(dateTzStr, new ParsePosition(0));
if (d != null) {
return d;
}
}
return null;
}
/**
* Convert a {@code Optional} into a String.
*
* @param d
* The Date to convert.
* @return The formatted date or null.
* @see java.text.SimpleDateFormat
*/
private static String getDateValue(Optional d) {
return d.map(PackagePropertiesPart::getDateValue).orElse("");
}
private static String getDateValue(Date d) {
SimpleDateFormat df = new SimpleDateFormat(DEFAULT_DATEFORMAT, Locale.ROOT);
df.setTimeZone(LocaleUtil.TIMEZONE_UTC);
return df.format(d);
}
@Override
protected InputStream getInputStreamImpl() {
throw new InvalidOperationException("Operation not authorized. This part may only be manipulated using the getters and setters on PackagePropertiesPart");
}
@Override
protected OutputStream getOutputStreamImpl() {
throw new InvalidOperationException(
"Can't use output stream to set properties !");
}
@Override
public boolean save(OutputStream zos) {
throw new InvalidOperationException("Operation not authorized. This part may only be manipulated using the getters and setters on PackagePropertiesPart");
}
@Override
public boolean load(InputStream ios) {
throw new InvalidOperationException("Operation not authorized. This part may only be manipulated using the getters and setters on PackagePropertiesPart");
}
@Override
public void close() {
// Do nothing
}
@Override
public void flush() {
// Do nothing
}
}