/***************************************************************************** * * 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; } }