/*****************************************************************************
*
* 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.padaf.xmpbox.schema;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.padaf.xmpbox.XMPMetadata;
import org.apache.padaf.xmpbox.type.AbstractField;
import org.apache.padaf.xmpbox.type.AbstractSimpleProperty;
import org.apache.padaf.xmpbox.type.Attribute;
import org.apache.padaf.xmpbox.type.BadFieldValueException;
import org.apache.padaf.xmpbox.type.BooleanType;
import org.apache.padaf.xmpbox.type.ComplexProperty;
import org.apache.padaf.xmpbox.type.ComplexPropertyContainer;
import org.apache.padaf.xmpbox.type.DateType;
import org.apache.padaf.xmpbox.type.Elementable;
import org.apache.padaf.xmpbox.type.IntegerType;
import org.apache.padaf.xmpbox.type.TextType;
import org.w3c.dom.Element;
/**
* This class represents a metadata schema that can be stored in an XMP
* document. It handles all generic properties that are available. See
* subclasses for access to specific properties. MODIFIED TO INCLUDE OBJECT
* REPRESENTATION
*
*/
public class XMPSchema implements Elementable {
/**
* The standard xmlns namespace.
*/
public static final String NS_NAMESPACE = "http://www.w3.org/2000/xmlns/";
public static final String RDFABOUT = "rdf:about";
protected String localPrefix, localNSUri;
protected String localPrefixSep;
protected XMPMetadata metadata;
protected ComplexPropertyContainer content;
/**
* Create a new blank schema that can be populated.
*
* @param metadata
* The parent XMP metadata that this schema will be part of.
* @param namespaceName
* The name of the namespace, ie pdf,dc,...
* @param namespaceURI
* The URI of the namespace, ie "http://ns.adobe.com/pdf/1.3/"
*
*/
public XMPSchema(XMPMetadata metadata, String namespaceName, String namespaceURI) {
this.metadata = metadata;
content = new ComplexPropertyContainer(metadata,
"http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdf",
"Description");
localPrefix = namespaceName;
localPrefixSep = localPrefix + ":";
localNSUri = namespaceURI;
content.setAttribute(new Attribute(NS_NAMESPACE, "xmlns",
namespaceName, namespaceURI));
}
/**
* Get the schema prefix
*
* @return Prefix fixed for the schema
*/
public String getPrefix() {
return localPrefix;
}
/**
* Get the namespace URI of this schema
*
* @return the namespace URI of this schema
*/
public String getNamespaceValue() {
return localNSUri;
}
/**
* Retrieve a generic simple type property
*
* @param qualifiedName
* Full qualified name of proeprty wanted
* @return The generic simple type property according to its qualified Name
*/
public AbstractField getAbstractProperty(String qualifiedName) {
Iterator<AbstractField> it = content.getAllProperties().iterator();
AbstractField tmp;
while (it.hasNext()) {
tmp = it.next();
if (tmp.getQualifiedName().equals(qualifiedName)) {
return tmp;
}
}
return null;
}
/**
* Get the RDF about attribute
*
* @return The RDF 'about' attribute.
*/
public Attribute getAboutAttribute() {
return content.getAttribute(RDFABOUT);
}
/**
* Get the RDF about value.
*
* @return The RDF 'about' value.
*/
public String getAboutValue() {
Attribute prop = content.getAttribute(RDFABOUT);
if (prop != null) {
return prop.getValue();
}
return null;
}
/**
* Set the RDF 'about' attribute
*
* @param about
* the well-formed attribute
* @throws BadFieldValueException
* Bad Attribute name (not corresponding to about attribute)
*/
public void setAbout(Attribute about) throws BadFieldValueException {
if (about.getQualifiedName().equals(RDFABOUT)
|| about.getQualifiedName().equals("about")) {
content.setAttribute(about);
} else {
throw new BadFieldValueException(
"Attribute 'about' must be named 'rdf:about' or 'about'");
}
}
/**
* Set the RDF 'about' attribute. Passing in null will clear this attribute.
*
* @param about
* The new RFD about value.
*/
public void setAboutAsSimple(String about) {
if (about == null) {
content.removeAttribute(RDFABOUT);
} else {
content.setAttribute(new Attribute(null, "rdf", "about", about));
}
}
/**
* Set a simple specified type property on the schema.
*
* @param type
* the property type
* @param qualifiedName
* the qualified name to specify for the new property
* @param propertyValue
* The value (must be an object understandable by specified type)
*/
@SuppressWarnings("unchecked")
private void setSpecifiedSimpleTypeProperty(
Class<? extends AbstractSimpleProperty> type, String qualifiedName,
Object propertyValue) {
String[] splittedQualifiedName = qualifiedName.split(":");
Class[] propertyArgsClass = new Class[] { XMPMetadata.class,
String.class, String.class, Object.class };
Object[] propertyArgs = new Object[] { metadata,
splittedQualifiedName[0], splittedQualifiedName[1],
propertyValue };
Constructor<? extends AbstractSimpleProperty> propertyConstructor;
AbstractSimpleProperty specifiedTypeProperty;
if (propertyValue == null) {
// Search in properties to erase
Iterator<AbstractField> it = content.getAllProperties().iterator();
AbstractField tmp;
while (it.hasNext()) {
tmp = it.next();
if (tmp.getQualifiedName().equals(qualifiedName)) {
content.removeProperty(tmp);
return;
}
}
} else {
try {
propertyConstructor = type.getConstructor(propertyArgsClass);
specifiedTypeProperty = (AbstractSimpleProperty) propertyConstructor
.newInstance(propertyArgs);
} catch (Exception e) {
throw new IllegalArgumentException(
"Failed to create property with the specified type given in parameters",
e);
}
// attribute placement for simple property has been removed
// Search in properties to erase
Iterator<AbstractField> it = content.getAllProperties().iterator();
AbstractField tmp;
while (it.hasNext()) {
tmp = it.next();
if (tmp.getQualifiedName().equals(qualifiedName)) {
content.removeProperty(tmp);
content.addProperty(specifiedTypeProperty);
return;
}
}
content.addProperty(specifiedTypeProperty);
}
}
/**
* Add a SimpleProperty to this schema
*
* @param prop
* The Property to add
*/
private void setSpecifiedSimpleTypeProperty(AbstractSimpleProperty prop) {
// attribute placement for simple property has been removed
// Search in properties to erase
Iterator<AbstractField> it = content.getAllProperties().iterator();
AbstractField tmp;
while (it.hasNext()) {
tmp = it.next();
if (tmp.getQualifiedName().equals(prop.getQualifiedName())) {
content.removeProperty(tmp);
content.addProperty(prop);
return;
}
}
content.addProperty(prop);
}
/**
* Set TextType property
*
* @param prop
* The text property to add
*/
public void setTextProperty(TextType prop) {
setSpecifiedSimpleTypeProperty(prop);
}
/**
* Set a simple text property on the schema.
*
* @param qualifiedName
* The name of the property, it must contain the namespace
* prefix, ie "pdf:Keywords"
* @param propertyValue
* The value for the property, can be any string. Passing null
* will remove the property.
*/
public void setTextPropertyValue(String qualifiedName, String propertyValue) {
setSpecifiedSimpleTypeProperty(TextType.class, qualifiedName,
propertyValue);
}
/**
* Set a simple text property on the schema, using the current prefix.
*
* @param simpleName
* the name of the property without prefix
* @param propertyValue
* The value for the property, can be any string. Passing null
* will remove the property.
*/
public void setTextPropertyValueAsSimple(String simpleName,
String propertyValue) {
this.setTextPropertyValue(localPrefixSep + simpleName, propertyValue);
}
/**
* Get a TextProperty Type from its name
*
* @param qualifiedName
* The full qualified name of the property wanted
* @return The Text Type property wanted
*/
public TextType getTextProperty(String qualifiedName) {
AbstractField prop = getAbstractProperty(qualifiedName);
if (prop != null) {
if (prop instanceof TextType) {
return (TextType) prop;
} else {
throw new IllegalArgumentException(
"Property asked is not a Text Property");
}
}
return null;
}
/**
* Get a simple text property value on the schema, using the current prefix.
*
* @param simpleName
* The local name of the property wanted
* @return The value of the text property or the null if there is no value.
*
*/
public String getTextPropertyValueAsSimple(String simpleName) {
return this.getTextPropertyValue(localPrefixSep + simpleName);
}
/**
* Get the value of a simple text property.
*
* @param qualifiedName
* The name of the property to get, it must include the namespace
* prefix. ie "pdf:Keywords".
*
* @return The value of the text property or the null if there is no value.
*
*/
public String getTextPropertyValue(String qualifiedName) {
AbstractField prop = getAbstractProperty(qualifiedName);
if (prop != null) {
if (prop instanceof TextType) {
return ((TextType) prop).getStringValue();
} else {
throw new IllegalArgumentException(
"Property asked is not a Text Property");
}
}
return null;
}
/**
* Get the Date property with its name
*
* @param qualifiedName
* The name of the property to get, it must include the namespace
* prefix. ie "pdf:Keywords".
* @return Date Type property
*
*/
public DateType getDateProperty(String qualifiedName) {
AbstractField prop = getAbstractProperty(qualifiedName);
if (prop != null) {
if (prop instanceof DateType) {
return (DateType) prop;
} else {
throw new IllegalArgumentException(
"Property asked is not a Date Property");
}
}
return null;
}
/**
* Get a simple date property value on the schema, using the current prefix.
*
* @param simpleName
* the local name of the property to get
* @return The value of the property as a calendar.
*
*/
public Calendar getDatePropertyValueAsSimple(String simpleName) {
return this.getDatePropertyValue(localPrefixSep + simpleName);
}
/**
* Get the value of the property as a date.
*
* @param qualifiedName
* The fully qualified property name for the date.
*
* @return The value of the property as a date.
*
*/
public Calendar getDatePropertyValue(String qualifiedName) {
AbstractField prop = getAbstractProperty(qualifiedName);
if (prop != null) {
if (prop instanceof DateType) {
return ((DateType) prop).getValue();
} else {
throw new IllegalArgumentException(
"Property asked is not a Date Property");
}
}
return null;
}
/**
* Set a new DateProperty
*
* @param date
* The DateType Property
*/
public void setDateProperty(DateType date) {
setSpecifiedSimpleTypeProperty(date);
}
/**
* Set a simple Date property on the schema, using the current prefix.
*
* @param simpleName
* the name of the property without prefix
* @param date
* The calendar value for the property, can be any string.
* Passing null will remove the property.
*/
public void setDatePropertyValueAsSimple(String simpleName, Calendar date) {
this.setDatePropertyValue(localPrefixSep + simpleName, date);
}
/**
* Set the value of the property as a date.
*
* @param qualifiedName
* The fully qualified property name for the date.
* @param date
* The date to set, or null to clear.
*/
public void setDatePropertyValue(String qualifiedName, Calendar date) {
setSpecifiedSimpleTypeProperty(DateType.class, qualifiedName, date);
}
/**
* Get a BooleanType property with its name
*
* @param qualifiedName
* the full qualified name of property wanted
* @return boolean Type property
*/
public BooleanType getBooleanProperty(String qualifiedName) {
AbstractField prop = getAbstractProperty(qualifiedName);
if (prop != null) {
if (prop instanceof BooleanType) {
return (BooleanType) prop;
} else {
throw new IllegalArgumentException(
"Property asked is not a Boolean Property");
}
}
return null;
}
/**
* Get a simple boolean property value on the schema, using the current
* prefix.
*
* @param simpleName
* the local name of property wanted
* @return The value of the property as a boolean.
*/
public Boolean getBooleanPropertyValueAsSimple(String simpleName) {
return this.getBooleanPropertyValue(localPrefixSep + simpleName);
}
/**
* Get the value of the property as a boolean.
*
* @param qualifiedName
* The fully qualified property name for the boolean.
*
* @return The value of the property as a boolean. Return null if property
* not exist
*/
public Boolean getBooleanPropertyValue(String qualifiedName) {
AbstractField prop = getAbstractProperty(qualifiedName);
if (prop != null) {
if (prop instanceof BooleanType) {
return ((BooleanType) prop).getValue();
} else {
throw new IllegalArgumentException(
"Property asked is not a Boolean Property");
}
}
// Return null if property not exist. This method give the property
// value so treat this return in this way.
// If you want to use this value like a condition, you must check this
// return before
return null;
}
/**
* Set a BooleanType property
*
* @param bool
* the booleanType property
*/
public void setBooleanProperty(BooleanType bool) {
setSpecifiedSimpleTypeProperty(bool);
}
/**
* Set a simple Boolean property on the schema, using the current prefix.
*
* @param simpleName
* the name of the property without prefix
* @param bool
* The value for the property, can be any string. Passing null
* will remove the property.
*/
public void setBooleanPropertyValueAsSimple(String simpleName, Boolean bool) {
this.setBooleanPropertyValue(localPrefixSep + simpleName, bool);
}
/**
* Set the value of the property as a boolean.
*
* @param qualifiedName
* The fully qualified property name for the boolean.
* @param bool
* The boolean to set, or null to clear.
*/
public void setBooleanPropertyValue(String qualifiedName, Boolean bool) {
setSpecifiedSimpleTypeProperty(BooleanType.class, qualifiedName, bool);
}
/**
* Get the Integer property with its name
*
* @param qualifiedName
* the full qualified name of property wanted
* @return Integer Type property
*/
public IntegerType getIntegerProperty(String qualifiedName) {
AbstractField prop = getAbstractProperty(qualifiedName);
if (prop != null) {
if (prop instanceof IntegerType) {
return ((IntegerType) prop);
} else {
throw new IllegalArgumentException(
"Property asked is not an Integer Property");
}
}
return null;
}
/**
* Get a simple integer property value on the schema, using the current
* prefix.
*
* @param simpleName
* the local name of property wanted
* @return The value of the property as an integer.
*/
public Integer getIntegerPropertyValueAsSimple(String simpleName) {
return this.getIntegerPropertyValue(localPrefixSep + simpleName);
}
/**
* Get the value of the property as an integer.
*
* @param qualifiedName
* The fully qualified property name for the integer.
*
* @return The value of the property as an integer.
*/
public Integer getIntegerPropertyValue(String qualifiedName) {
AbstractField prop = getAbstractProperty(qualifiedName);
if (prop != null) {
if (prop instanceof IntegerType) {
return ((IntegerType) prop).getValue();
} else {
throw new IllegalArgumentException(
"Property asked is not an Integer Property");
}
}
return null;
}
/**
* Add an integerProperty
*
* @param prop
* The Integer Type property
*/
public void setIntegerProperty(IntegerType prop) {
setSpecifiedSimpleTypeProperty(prop);
}
/**
* Set a simple Integer property on the schema, using the current prefix.
*
* @param simpleName
* the name of the property without prefix
* @param intValue
* The value for the property, can be any string. Passing null
* will remove the property.
*/
public void setIntegerPropertyValueAsSimple(String simpleName,
Integer intValue) {
this.setIntegerPropertyValue(localPrefixSep + simpleName, intValue);
}
/**
* Set the value of the property as an integer.
*
* @param qualifiedName
* The fully qualified property name for the integer.
* @param intValue
* The int to set, or null to clear.
*/
public void setIntegerPropertyValue(String qualifiedName, Integer intValue) {
setSpecifiedSimpleTypeProperty(IntegerType.class, qualifiedName,
intValue);
}
/**
* Generic array property removing
*
* @param qualifiedArrayName
* the full qualified name of property wanted
* @param fieldValue
* the field value
*/
private void removeArrayValue(String qualifiedArrayName, String fieldValue) {
ComplexProperty array = (ComplexProperty) getAbstractProperty(qualifiedArrayName);
if (array != null) {
ArrayList<AbstractField> toDelete = new ArrayList<AbstractField>();
Iterator<AbstractField> it = array.getContainer()
.getAllProperties().iterator();
AbstractSimpleProperty tmp;
while (it.hasNext()) {
tmp = (AbstractSimpleProperty) it.next();
if (tmp.getStringValue().equals(fieldValue)) {
toDelete.add(tmp);
}
}
Iterator<AbstractField> eraseProperties = toDelete.iterator();
while (eraseProperties.hasNext()) {
array.getContainer().removeProperty(eraseProperties.next());
}
}
}
/**
* Remove all matching entries with the given value from the bag.
*
* @param qualifiedBagName
* The name of the bag, it must include the namespace prefix. ie
* "pdf:Keywords".
* @param bagValue
* The value to remove from the bagList.
*/
public void removeBagValue(String qualifiedBagName, String bagValue) {
removeArrayValue(qualifiedBagName, bagValue);
}
/**
* add a bag value property on the schema, using the current prefix.
*
* @param simpleName
* the local name of property
* @param bagValue
* the string value to add
*/
public void addBagValueAsSimple(String simpleName, String bagValue) {
this.addBagValue(localPrefixSep + simpleName, bagValue);
}
/**
* Add an entry to a bag property.
*
* @param qualifiedBagName
* The name of the bag, it must include the namespace prefix. ie
* "pdf:Keywords".
* @param bagValue
* The value to add to the bagList.
*/
public void addBagValue(String qualifiedBagName, String bagValue) {
String[] splittedQualifiedName = qualifiedBagName.split(":");
ComplexProperty bag = (ComplexProperty) getAbstractProperty(qualifiedBagName);
TextType li = new TextType(metadata, "rdf", "li", bagValue);
if (bag != null) {
bag.getContainer().addProperty(li);
} else {
ComplexProperty newBag = new ComplexProperty(metadata,
splittedQualifiedName[0], splittedQualifiedName[1],
ComplexProperty.UNORDERED_ARRAY);
newBag.getContainer().addProperty(li);
content.addProperty(newBag);
}
}
/**
* Generic String List Builder for arrays contents
*
* @param qualifiedArrayName
* the full qualified name of property concerned
* @return String list which represents content of array property
*/
private List<String> getArrayListToString(String qualifiedArrayName) {
List<String> retval = null;
ComplexProperty array = (ComplexProperty) getAbstractProperty(qualifiedArrayName);
if (array != null) {
retval = new ArrayList<String>();
Iterator<AbstractField> it = array.getContainer()
.getAllProperties().iterator();
AbstractSimpleProperty tmp;
while (it.hasNext()) {
tmp = (AbstractSimpleProperty) it.next();
retval.add(tmp.getStringValue());
}
retval = Collections.unmodifiableList(retval);
}
return retval;
}
/**
* Get all the values of the bag property, using the current prefix. This
* will return a list of java.lang.String objects, this is a read-only list.
*
* @param simpleName
* the local name of property concerned
*
*
* @return All values of the bag property in a list.
*/
public List<String> getBagValueListAsSimple(String simpleName) {
return getBagValueList(localPrefixSep + simpleName);
}
/**
* Get all the values of the bag property. This will return a list of
* java.lang.String objects, this is a read-only list.
*
* @param qualifiedBagName
* The name of the bag property to get, it must include the
* namespace prefix. ie "pdf:Keywords"
*
* @return All values of the bag property in a list.
*/
public List<String> getBagValueList(String qualifiedBagName) {
return getArrayListToString(qualifiedBagName);
}
/**
* Remove all matching values from a sequence property.
*
* @param qualifiedSeqName
* The name of the sequence property. It must include the
* namespace prefix. ie "pdf:Keywords".
* @param seqValue
* The value to remove from the list.
*/
public void removeSequenceValue(String qualifiedSeqName, String seqValue) {
removeArrayValue(qualifiedSeqName, seqValue);
}
/**
* Generic method to remove a field from an array with an Elementable Object
*
* @param qualifiedArrayName
* the full qualified name of the property concerned
* @param fieldValue
* the elementable field value
*/
public void removeArrayValue(String qualifiedArrayName,
Elementable fieldValue) {
ComplexProperty array = (ComplexProperty) getAbstractProperty(qualifiedArrayName);
if (array != null) {
ArrayList<AbstractField> toDelete = new ArrayList<AbstractField>();
Iterator<AbstractField> it = array.getContainer()
.getAllProperties().iterator();
AbstractSimpleProperty tmp;
while (it.hasNext()) {
tmp = (AbstractSimpleProperty) it.next();
if (tmp.equals(fieldValue)) {
toDelete.add(tmp);
}
}
Iterator<AbstractField> eraseProperties = toDelete.iterator();
while (eraseProperties.hasNext()) {
array.getContainer().removeProperty(eraseProperties.next());
}
}
}
/**
* Remove a value from a sequence property. This will remove all entries
* from the list.
*
* @param qualifiedSeqName
* The name of the sequence property. It must include the
* namespace prefix. ie "pdf:Keywords".
* @param seqValue
* The value to remove from the list.
*/
public void removeSequenceValue(String qualifiedSeqName,
Elementable seqValue) {
removeArrayValue(qualifiedSeqName, seqValue);
}
/**
* Add a new value to a sequence property.
*
* @param qualifiedSeqName
* The name of the sequence property, it must include the
* namespace prefix. ie "pdf:Keywords"
* @param seqValue
* The value to add to the sequence.
*/
public void addSequenceValue(String qualifiedSeqName, String seqValue) {
String[] splittedQualifiedName = qualifiedSeqName.split(":");
ComplexProperty seq = (ComplexProperty) getAbstractProperty(qualifiedSeqName);
TextType li = new TextType(metadata, "rdf", "li", seqValue);
if (seq != null) {
seq.getContainer().addProperty(li);
} else {
ComplexProperty newSeq = new ComplexProperty(metadata,
splittedQualifiedName[0], splittedQualifiedName[1],
ComplexProperty.ORDERED_ARRAY);
newSeq.getContainer().addProperty(li);
content.addProperty(newSeq);
}
}
/**
* Add a new value to a bag property.
*
* @param qualifiedSeqName
* The name of the sequence property, it must include the
* namespace prefix. ie "pdf:Keywords"
* @param seqValue
* The value to add to the bag.
*/
public void addBagValue(String qualifiedSeqName, AbstractField seqValue) {
String[] splittedQualifiedName = qualifiedSeqName.split(":");
ComplexProperty bag = (ComplexProperty) getAbstractProperty(qualifiedSeqName);
if (bag != null) {
bag.getContainer().addProperty(seqValue);
} else {
ComplexProperty newBag = new ComplexProperty(metadata,
splittedQualifiedName[0], splittedQualifiedName[1],
ComplexProperty.UNORDERED_ARRAY);
newBag.getContainer().addProperty(seqValue);
content.addProperty(newBag);
}
}
/**
* add a new value to a sequence property using the current prefix.
*
* @param simpleName
* the local name of the property
* @param seqValue
* the string value to add
*/
public void addSequenceValueAsSimple(String simpleName, String seqValue) {
this.addSequenceValue(localPrefixSep + simpleName, seqValue);
}
/**
* Add a new value to a sequence property.
*
* @param qualifiedSeqName
* The name of the sequence property, it must include the
* namespace prefix. ie "pdf:Keywords"
* @param seqValue
* The value to add to the sequence.
*/
public void addSequenceValue(String qualifiedSeqName, AbstractField seqValue) {
String[] splittedQualifiedName = qualifiedSeqName.split(":");
ComplexProperty seq = (ComplexProperty) getAbstractProperty(qualifiedSeqName);
if (seq != null) {
seq.getContainer().addProperty(seqValue);
} else {
ComplexProperty newSeq = new ComplexProperty(metadata,
splittedQualifiedName[0], splittedQualifiedName[1],
ComplexProperty.ORDERED_ARRAY);
newSeq.getContainer().addProperty(seqValue);
content.addProperty(newSeq);
}
}
/**
* Get all the values in a sequence property, using the current prefix.
*
* @param simpleName
* the local name of the property
* @return A read-only list of java.lang.String objects or null if the
* property does not exist.
*/
public List<String> getSequenceValueListAsSimple(String simpleName) {
return this.getSequenceValueList(localPrefixSep + simpleName);
}
/**
* Get all the values in a sequence property.
*
* @param qualifiedSeqName
* The name of the sequence property, it must include the
* namespace prefix. ie "pdf:Keywords".
*
* @return A read-only list of java.lang.String objects or null if the
* property does not exist.
*/
public List<String> getSequenceValueList(String qualifiedSeqName) {
return getArrayListToString(qualifiedSeqName);
}
/**
* Remove a date sequence value from the list.
*
* @param qualifiedSeqName
* The name of the sequence property, it must include the
* namespace prefix. ie "pdf:Keywords"
* @param date
* The date to remove from the sequence property.
*/
public void removeSequenceDateValue(String qualifiedSeqName, Calendar date) {
ComplexProperty seq = (ComplexProperty) getAbstractProperty(qualifiedSeqName);
if (seq != null) {
ArrayList<AbstractField> toDelete = new ArrayList<AbstractField>();
Iterator<AbstractField> it = seq.getContainer().getAllProperties()
.iterator();
AbstractField tmp;
while (it.hasNext()) {
tmp = it.next();
if (tmp instanceof DateType) {
if (((DateType) tmp).getValue().equals(date)) {
toDelete.add(tmp);
}
}
}
Iterator<AbstractField> eraseProperties = toDelete.iterator();
while (eraseProperties.hasNext()) {
seq.getContainer().removeProperty(eraseProperties.next());
}
}
}
/**
* Add a date sequence value to the list using the current prefix
*
* @param simpleName
* the local name of the property
* @param date
* the value to add
*/
public void addSequenceDateValueAsSimple(String simpleName, Calendar date) {
addSequenceDateValue(localPrefixSep + simpleName, date);
}
/**
* Add a date sequence value to the list.
*
* @param qualifiedSeqName
* The name of the sequence property, it must include the
* namespace prefix. ie "pdf:Keywords"
* @param date
* The date to add to the sequence property.
*/
public void addSequenceDateValue(String qualifiedSeqName, Calendar date) {
addSequenceValue(qualifiedSeqName, new DateType(metadata, "rdf", "li",
date));
}
/**
* Get all the date values in a sequence property, using the current prefix.
*
* @param simpleName
* the local name of property concerned
* @return A read-only list of java.util.Calendar objects or null if the
* property does not exist.
*/
public List<Calendar> getSequenceDateValueListAsSimple(String simpleName) {
return this.getSequenceDateValueList(localPrefixSep + simpleName);
}
/**
* Get all the date values in a sequence property.
*
* @param qualifiedSeqName
* The name of the sequence property, it must include the
* namespace prefix. ie "pdf:Keywords".
*
* @return A read-only list of java.util.Calendar objects or null if the
* property does not exist.
*
*/
public List<Calendar> getSequenceDateValueList(String qualifiedSeqName) {
List<Calendar> retval = null;
ComplexProperty seq = (ComplexProperty) getAbstractProperty(qualifiedSeqName);
if (seq != null) {
retval = new ArrayList<Calendar>();
Iterator<AbstractField> it = seq.getContainer().getAllProperties()
.iterator();
AbstractField tmp;
while (it.hasNext()) {
tmp = it.next();
if (tmp instanceof DateType) {
retval.add(((DateType) tmp).getValue());
}
}
}
return retval;
}
/**
* Method used to place the 'x-default' value in first in Language
* alternatives as said in xmp spec
*
* @param alt
* The property to reorganize
*/
public void reorganizeAltOrder(ComplexPropertyContainer alt) {
Iterator<AbstractField> it = alt.getAllProperties().iterator();
AbstractField xdefault = null;
boolean xdefaultFound = false;
// If alternatives contains x-default in first value
if (it.hasNext()) {
if (it.next().getAttribute("xml:lang").getValue().equals(
"x-default")) {
return;
}
}
// Find the xdefault definition
while (it.hasNext() && !xdefaultFound) {
xdefault = it.next();
if (xdefault.getAttribute("xml:lang").getValue()
.equals("x-default")) {
alt.removeProperty(xdefault);
xdefaultFound = true;
}
}
if (xdefaultFound) {
it = alt.getAllProperties().iterator();
ArrayList<AbstractField> reordered = new ArrayList<AbstractField>();
ArrayList<AbstractField> toDelete = new ArrayList<AbstractField>();
reordered.add(xdefault);
AbstractField tmp;
while (it.hasNext()) {
tmp = it.next();
reordered.add(tmp);
toDelete.add(tmp);
}
Iterator<AbstractField> eraseProperties = toDelete.iterator();
while (eraseProperties.hasNext()) {
alt.removeProperty(eraseProperties.next());
}
it = reordered.iterator();
while (it.hasNext()) {
alt.addProperty(it.next());
}
}
}
/**
* Set a multi-lingual property on the schema, using the current prefix.
*
* @param simpleName
* the local name of the property
* @param language
* the language concerned
* @param value
* the value to set for the language specified
*/
public void setLanguagePropertyValueAsSimple(String simpleName,
String language, String value) {
this.setLanguagePropertyValue(localPrefixSep + simpleName, language,
value);
}
/**
* Set the value of a multi-lingual property.
*
* @param qualifiedName
* The name of the property, it must include the namespace
* prefix. ie "pdf:Keywords"
* @param language
* The language code of the value. If null then "x-default" is
* assumed.
* @param value
* The value of the property in the specified language.
*/
public void setLanguagePropertyValue(String qualifiedName, String language,
String value) {
AbstractField property = getAbstractProperty(qualifiedName);
ComplexProperty prop;
if (property != null) {
// Analyzing content of property
if (property instanceof ComplexProperty) {
prop = (ComplexProperty) property;
Iterator<AbstractField> itCplx = prop.getContainer()
.getAllProperties().iterator();
// try to find the same lang definition
AbstractField tmp;
// Try to find a definition
while (itCplx.hasNext()) {
tmp = itCplx.next();
// System.err.println(tmp.getAttribute("xml:lang").getStringValue());
if (tmp.getAttribute("xml:lang").getValue()
.equals(language)) {
// the same language has been found
if (value == null) {
// if value null, erase this definition
prop.getContainer().removeProperty(tmp);
} else {
prop.getContainer().removeProperty(tmp);
TextType langValue;
langValue = new TextType(metadata, "rdf", "li",
value);
langValue.setAttribute(new Attribute(null, "xml",
"lang", language));
prop.getContainer().addProperty(langValue);
}
reorganizeAltOrder(prop.getContainer());
return;
}
}
// if no definition found, we add a new one
TextType langValue;
langValue = new TextType(metadata, "rdf", "li", value);
langValue.setAttribute(new Attribute(null, "xml", "lang",
language));
prop.getContainer().addProperty(langValue);
reorganizeAltOrder(prop.getContainer());
}
} else {
String[] splittedQualifiedName = qualifiedName.split(":");
prop = new ComplexProperty(metadata, splittedQualifiedName[0],
splittedQualifiedName[1], ComplexProperty.ALTERNATIVE_ARRAY);
TextType langValue;
langValue = new TextType(metadata, "rdf", "li", value);
langValue
.setAttribute(new Attribute(null, "xml", "lang", language));
prop.getContainer().addProperty(langValue);
content.addProperty(prop);
}
}
/**
* Get the value of a multi-lingual property, using the current prefix.
*
* @param simpleName
* the local name of the property
* @param language
* The language code of the value. If null then "x-default" is
* assumed.
*
* @return The value of the language property.
*/
public String getLanguagePropertyValueAsSimple(String simpleName,
String language) {
return this.getLanguagePropertyValue(localPrefixSep + simpleName,
language);
}
/**
* Get the value of a multi-lingual property.
*
* @param qualifiedName
* The name of the property, it must include the namespace
* prefix. ie "pdf:Keywords"
* @param language
* The language code of the value. If null then "x-default" is
* assumed.
*
* @return The value of the language property.
*/
public String getLanguagePropertyValue(String qualifiedName, String expectedLanguage) {
String language = (expectedLanguage!=null)?expectedLanguage:"x-default";
AbstractField property = getAbstractProperty(qualifiedName);
if (property != null) {
if (property instanceof ComplexProperty) {
ComplexProperty prop = (ComplexProperty) property;
Iterator<AbstractField> langsDef = prop.getContainer()
.getAllProperties().iterator();
AbstractField tmp;
Attribute text;
while (langsDef.hasNext()) {
tmp = langsDef.next();
text = tmp.getAttribute("xml:lang");
if (text != null) {
if (text.getValue().equals(language)) {
return ((TextType) tmp).getStringValue();
}
}
}
return null;
} else {
throw new IllegalArgumentException("The property '"
+ qualifiedName + "' is not of Lang Alt type");
}
}
return null;
}
/**
* Get a list of all languages that are currently defined for a specific
* property, using the current prefix.
*
* @param simpleName
* the local name of the property
* @return A list of all languages, this will return an non-null empty list
* if none have been defined.
*/
public List<String> getLanguagePropertyLanguagesValueAsSimple(
String simpleName) {
return this.getLanguagePropertyLanguagesValue(localPrefixSep
+ simpleName);
}
/**
* Get a list of all languages that are currently defined for a specific
* property.
*
* @param qualifiedName
* The name of the property, it must include the namespace
* prefix. ie "pdf:Keywords"
*
* @return A list of all languages, this will return an non-null empty list
* if none have been defined.
*/
public List<String> getLanguagePropertyLanguagesValue(String qualifiedName) {
List<String> retval = new ArrayList<String>();
AbstractField property = getAbstractProperty(qualifiedName);
if (property != null) {
if (property instanceof ComplexProperty) {
ComplexProperty prop = (ComplexProperty) property;
Iterator<AbstractField> langsDef = prop.getContainer()
.getAllProperties().iterator();
AbstractField tmp;
Attribute text;
while (langsDef.hasNext()) {
tmp = langsDef.next();
text = tmp.getAttribute("xml:lang");
if (text != null) {
retval.add(text.getValue());
} else {
retval.add("x-default");
}
}
return retval;
} else {
throw new IllegalArgumentException("The property '"
+ qualifiedName + "' is not of Lang Alt type");
}
}
// no property with that name
return null;
}
/**
* A basic schema merge, it merges bags and sequences and replace everything
* else.
*
* @param xmpSchema
* The schema to merge.
* @throws IOException
* If there is an error during the merge.
*/
public void merge(XMPSchema xmpSchema) throws IOException {
if (!xmpSchema.getClass().equals(this.getClass())) {
throw new IOException("Can only merge schemas of the same type.");
}
Iterator<Attribute> itAtt = xmpSchema.content.getAllAttributes()
.iterator();
Attribute att;
while (itAtt.hasNext()) {
att = itAtt.next();
if (att.getPrefix().equals(getPrefix())) {
content.setAttribute(att);
}
}
String analyzedPropQualifiedName;
Iterator<AbstractField> itProp = xmpSchema.content.getAllProperties()
.iterator();
AbstractField prop;
while (itProp.hasNext()) {
prop = itProp.next();
if (prop.getPrefix().equals(getPrefix())) {
if (prop instanceof ComplexProperty) {
analyzedPropQualifiedName = prop.getQualifiedName();
Iterator<AbstractField> itActualEmbeddedProperties = content
.getAllProperties().iterator();
AbstractField tmpEmbeddedProperty;
Iterator<AbstractField> itNewValues;
TextType tmpNewValue;
Iterator<AbstractField> itOldValues;
TextType tmpOldValue;
boolean alreadyPresent = false;
while (itActualEmbeddedProperties.hasNext()) {
tmpEmbeddedProperty = itActualEmbeddedProperties.next();
if (tmpEmbeddedProperty instanceof ComplexProperty) {
if (tmpEmbeddedProperty.getQualifiedName().equals(
analyzedPropQualifiedName)) {
itNewValues = ((ComplexProperty) prop)
.getContainer().getAllProperties()
.iterator();
// Merge a complex property
while (itNewValues.hasNext()) {
tmpNewValue = (TextType) itNewValues.next();
itOldValues = ((ComplexProperty) tmpEmbeddedProperty)
.getContainer().getAllProperties()
.iterator();
while (itOldValues.hasNext()
&& !alreadyPresent) {
tmpOldValue = (TextType) itOldValues
.next();
if (tmpOldValue
.getStringValue()
.equals(
tmpNewValue
.getStringValue())) {
alreadyPresent = true;
}
}
if (!alreadyPresent) {
((ComplexProperty) tmpEmbeddedProperty)
.getContainer().addProperty(
tmpNewValue);
}
}
}
}
}
} else {
content.addProperty(prop);
}
}
}
}
/**
* Get an AbstractField list corresponding to the content of an array Return
* null if the property is unknown
*
* @param qualifiedName
* the full qualified name of the property concerned
* @return List of property contained in the complex property
* @throws BadFieldValueException
* Property not contains property (not complex property)
*/
public List<AbstractField> getArrayList(String qualifiedName)
throws BadFieldValueException {
ComplexProperty array = null;
Iterator<AbstractField> itProp = content.getAllProperties().iterator();
AbstractField tmp;
while (itProp.hasNext()) {
tmp = itProp.next();
if (tmp.getQualifiedName().equals(qualifiedName)) {
if (tmp instanceof ComplexProperty) {
array = (ComplexProperty) tmp;
break;
} else {
throw new BadFieldValueException(
"Property asked not seems to be an array");
}
}
}
if (array != null) {
Iterator<AbstractField> it = array.getContainer()
.getAllProperties().iterator();
List<AbstractField> list = new ArrayList<AbstractField>();
while (it.hasNext()) {
list.add(it.next());
}
return list;
}
return null;
}
/**
* Get PropertyContainer of this Schema
*
* @return the ComplexProperty which represents the schema content
*/
public ComplexPropertyContainer getContent() {
return content;
}
/**
* Get All attributes defined for this schema
*
* @return Attributes list defined for this schema
*/
public List<Attribute> getAllAttributes() {
return content.getAllAttributes();
}
/**
* Get All properties defined in this schema
*
* @return Properties list defined in this schema
*/
public List<AbstractField> getAllProperties() {
return content.getAllProperties();
}
/**
* Set a new attribute for this schema
*
* @param attr
* The new Attribute to set
*/
public void setAttribute(Attribute attr) {
content.setAttribute(attr);
}
/**
* Add a new Property to this schema
*
* @param obj
* The new property to add
*/
public void addProperty(AbstractField obj) {
content.addProperty(obj);
}
/**
* Get DOM Element for rdf/xml serialization
*
* @return the DOM Element
*/
public Element getElement() {
return content.getElement();
}
/**
* get a Property with its name, using the current prefix
*
* @param simpleName
* the local name of the property
* @return The property wanted
*/
protected AbstractField getPropertyAsSimple(String simpleName) {
return getProperty(localPrefixSep + simpleName);
}
/**
* get a Property with its qualified Name (with its prefix)
*
* @param qualifiedName
* The full qualified name of the property wanted
* @return the property wanted
*/
protected AbstractField getProperty(String qualifiedName) {
Iterator<AbstractField> it = getAllProperties().iterator();
AbstractField tmp;
while (it.hasNext()) {
tmp = it.next();
if (tmp.getQualifiedName().equals(qualifiedName)) {
return tmp;
}
}
return null;
}
/**
* Return local prefix
*
* @return current prefix fixed for this schema
*/
public String getLocalPrefix() {
return this.localPrefix;
}
/**
* Return local prefix with separator
*
* @return current prefix fixed for this schema with ':' separator
*/
public String getLocalPrefixWithSeparator() {
return this.localPrefixSep;
}
}