package org.greenstone.gsdl3.gs3build.metadata;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.HashMap;
import org.greenstone.gsdl3.gs3build.util.MultiMap;
import org.greenstone.gsdl3.gs3build.util.XMLTools;
/**
* Implement a generic, ordered namespace in METS.
*
* @see: org.greenstone.gsdl3.gs3build.metadata.METSNamespace
*/
public class OrderedNamespace extends METSNamespace
{
List metadataList;
public OrderedNamespace(String name)
{
super(name);
this.metadataList = new ArrayList();
}
public OrderedNamespace(String name, METSLocation location)
{
super(name, location);
this.metadataList = new ArrayList();
}
public boolean validate(String field, String value)
{
return true;
}
/**
* Add a metadata item. Whether the field and value validate for this
* schema will also be tested.
*
* @param String
the name of the field to be given the value
* @param String
the value to be assigned
*
* @return boolean
whether the field value was added. This
* would return false
if the values did not validate,
* for example.
*/
public boolean addMetadata(String label, String value)
{
if (!this.validate(label, value)) {
return false;
}
this.metadataList.add(new NamespaceItem(label, value));
return true;
}
/**
* Assign a metadata item. Whether the field and value validate for this
* schema will also be tested. Any existing metadata for that field will
* be destroyed if the new value validates.
*
* @param String
the name of the field to be given the value
* @param String
the value to be assigned
*
* @return boolean
whether the field value was added. This
* would return false
if the values did not validate,
* for example.
*/
public boolean setMetadata(String label, String value)
{
if (!this.validate(label, value)){
return false;
}
// TODO: this.metadataMap.setOnly(label, value);
int itemNo = this.findItem(label);
if (itemNo >= 0){
this.metadataList.set(itemNo, new NamespaceItem(label, value));
return true;
}
return false;
}
/**
* Remove all metadata values for a given field name
*
* @param String
the field to delete
*
* @return boolean
whether the field was actually deleted;
* will return true
if the field was already empty.
*/
public boolean removeMetadata(String label)
{
int itemNo;
itemNo = this.findItem(label);
while (itemNo >= 0){
this.metadataList.remove(itemNo);
itemNo = this.findItem(label);
}
return true;
}
/**
* Remove a particular incidence of a given metadata field for a document.
* If an exact match for the given value is not found, nothing changes.
* N.B. if a value occurs twice, only the first incidence of it will be
* deleted from the list.
*
* @param String
the field to have the value removed
* @param String
the value to be removed from a given field
*
* @return boolean
true
if an actual metadata text
* is matched against the given value and is thus deleted.
*/
public boolean removeMetadata(String label, String value)
{
int itemNo;
itemNo = this.findItem(label);
if (itemNo >= 0) {
this.metadataList.remove(itemNo);
return true;
}
return false;
}
/**
* Get the metadata items for a particular label
*
* @param String
the label to fetch values for - must be devoid
* of namespace prologue (i.e. "title" rather than
* e.g. "dc:title").
*
* @return List
the list of corresponding values. May be
* null
if no values are found for the metadata
*/
public List getMetadata(String label)
{
List resultList = new ArrayList();
for (int i = 0; i < this.metadataList.size(); i ++) {
NamespaceItem item = (NamespaceItem) this.metadataList.get(i);
if (item.getLabel().equals(label)){
resultList.add(item.getValue());
}
}
if (resultList.size() > 0){
return resultList;
}
return null;
}
private int findItem(String label)
{
for (int i = 0; i < this.metadataList.size(); i ++) {
if (((NamespaceItem) this.metadataList.get(i)).getLabel().equals(label)){
return i;
}
}
return -1;
}
private int findItem(String label, String value)
{
for (int i = 0; i < this.metadataList.size(); i ++){
NamespaceItem item = (NamespaceItem) this.metadataList.get(i);
if (item.getLabel().equals(label) && item.getValue().equals(value)){
return i;
}
}
return -1;
}
public Iterator getMetadataNames()
{
return this.metadataList.iterator();
}
/**
* Write out the metadata to an XML file through a PrintWriter
.
*
* @param PrintWriter
the writer to use.
*/
public boolean write(PrintWriter writer)
{
// if this is a non-file block of metadata, write it out in long hand
if (this.location == null){
String tag = XMLTools.getOpenTag("mets", "mdWrap");
tag = XMLTools.addAttribute(tag, "MDTYPE", "OTHER");
tag = XMLTools.addAttribute(tag, "OTHERMDTYPE", this.name);
if (this.id != null) {
this.id = "gsdl"+this.id;
tag = XMLTools.addAttribute(tag, "ID", this.id);
}
writer.print(" "); //indentation
writer.println(tag);
Iterator items = this.metadataList.iterator();
while (items.hasNext()){
NamespaceItem item = (NamespaceItem) items.next();
this.writeItem(writer, item);
}
writer.print(" "); //indentation
writer.println("");
}
// otherwise, drop the metadata out in a simplified file-reference
// form only
else
{
String tag = XMLTools.getOpenTag("mets", "mdRef");
tag = XMLTools.addAttribute(tag, "LOCTYPE", this.location.getType());
tag = XMLTools.addAttribute(tag, "xlink:href", this.location.getLocation().toString());
tag = XMLTools.addAttribute(tag, "MDTYPE", this.name);
//tag = XMLTools.addAttribute (tag, "MDTYPE", "OTHER");
//tag = XMLTools.addAttribute(tag, "OTHERMDTYPE", this.name);
if (this.id != null) {
tag = XMLTools.addAttribute(tag, "ID", this.id);
}
tag = XMLTools.makeSingleton(tag);
}
return true;
}
/**
* Write out a single element - this may be overloaded to provide for the
* appropriate formatting for this metadata.
*/
protected boolean writeItem(PrintWriter writer, NamespaceItem item)
{
// Do some default sillinesses
//writer.write(" ");
writer.write(XMLTools.getOpenTag(this.name, item.getLabel()));
writer.write(item.getValue());
writer.write(XMLTools.getCloseTag(this.name, item.getLabel()));
return true;
}
/**
*
Indicate whether this metadata is open to being changed or not.
*Metadata which is created from a distinct file cannot be changed,
* only those which have no associated file can be modified.
*
* @return boolean
whether this namespace can be altered.
*/
public boolean isEditable()
{
return (this.location == null);
}
}