package org.greenstone.gatherer.msm; /** *######################################################################### * * A component of the Gatherer application, part of the Greenstone digital * library suite from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * *

* * Author: John Thompson, Greenstone Digital Library, University of Waikato * *

* * Copyright (C) 1999 New Zealand Digital Library Project * *

* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * *

* * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * *

* * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *######################################################################## */ import java.io.*; import java.util.*; import org.greenstone.gatherer.Gatherer; import org.greenstone.gatherer.msm.ElementWrapper; import org.greenstone.gatherer.msm.GDMManager; import org.greenstone.gatherer.msm.Metadata; import org.greenstone.gatherer.msm.MetadataSetManager; import org.greenstone.gatherer.msm.MSMUtils; import org.greenstone.gatherer.util.ArrayTools; import org.greenstone.gatherer.util.Utility; import org.greenstone.gatherer.valuetree.GValueModel; import org.greenstone.gatherer.valuetree.GValueNode; import org.w3c.dom.*; /** This class wraps around a DOM Document providing methods for accessing the data within. In this case the DOM represents a Greenstone Directory metadata file. It provides the necessary functionality to create a new metadata.xml file. */ public class GDMDocument { /** The document this class sources its data from. */ private Document document; /** The pattern to match when searching for directory level assignments. */ static final private String DIRECTORY_FILENAME = ".*"; /** @deprecated */ public GDMDocument(Gatherer gatherer, File file) {} /** @deprecated */ public GDMDocument(Gatherer gatherer, File file, Document document) {} /** Constructor which creates a brand new metadata.xml document. */ public GDMDocument() { // Create new document. We do this by loading a copy of the template. */ this.document = Utility.parse(Utility.GREENSTONEDIRECTORYMETADATA_TEMPLATE, true); } /** Constructor which parses an existing metadata.xml document. */ public GDMDocument(File file) { try { this.document = Utility.parse(file.getAbsolutePath(), false); } catch (Exception error) { // Poorly formed, or completely invalid metadata.xml file! } } /** Constructor which wraps around an existing metadata.xml document. */ public GDMDocument(Document document) { this.document = document; } /** Add this piece of directory level metadata. */ public void addDirectoryMetadata(Metadata metadata) { addMetadata(DIRECTORY_FILENAME, metadata); } /** Add a new piece of metadata to this document, for the given filename. */ public void addMetadata(String filename, Metadata metadata) { try { Element fileset_element = getFileSet(filename); // Retrieve the Metadata Element for this fileset. Element description_element = (Element) MSMUtils.getNodeFromNamed(fileset_element, "Description"); // Add the new element. Element metadata_element = document.createElement("Metadata"); metadata_element.setAttribute("name", metadata.getElement().getName()); // What mode we use depends on whether this is the first metadata assignment of this type. If so we use overwrite to ensure that it overrides any directory level metadata (overwrite is the default mode). If this isn't the first metadata of this type we explicitly set accumulate. if(existsMetadata(description_element, metadata.getElement().toString())) { metadata_element.setAttribute("mode", "accumulate"); } // What actually gets written at the node depends on whether the element above is a hierarchy based one. GValueModel model = MetadataSetManager.self.getValueTree(metadata.getElement()); Text metadata_element_value; if(model != null && model.isHierarchy()) { metadata_element_value = document.createTextNode(model.getHIndex(metadata.getAbsoluteValue())); } else { metadata_element_value = document.createTextNode(metadata.getValue()); } metadata_element.appendChild(metadata_element_value); } catch (Exception error) { Gatherer.printStackTrace(error); } } /** @deprecated */ public void destroy() {} /** Retrieve the document this class is wrapping. */ public Document getDocument() { return document; } /** @deprecated */ public File getFile() { return null; } /** Get all of the metadata, including directory level, associated with this file. If remove is true remove any metadata we find. */ public ArrayList getMetadata(String filename, boolean remove) { Metadata[] metadatum = null; try { // Retrieve the document element. Element directorymetadata_element = document.getDocumentElement(); // Iterate through the filesets, checking the FileName child element against the target file's name using regular expression matching. NodeList filesets = directorymetadata_element.getElementsByTagName("FileSet"); for(int i = 0; i < filesets.getLength(); i++) { Element fileset_element = (Element) filesets.item(i); Element filename_element = (Element) MSMUtils.getNodeFromNamed(fileset_element, "FileName"); String current_filename = MSMUtils.getValue(filename_element); if((filename != null && current_filename.matches(filename)) || current_filename.equals(DIRECTORY_FILENAME)) { // If they match add all of the metadata found in the Description child element, remembering to abide by desired mode (accumulate vs. overwrite). Element description_element = (Element)MSMUtils.getNodeFromNamed(fileset_element, "Description"); NodeList metadatas = description_element.getElementsByTagName("Metadata"); for(int j = 0; j < metadatas.getLength(); j++) { Element metadata_element = (Element) metadatas.item(j); String element_str = metadata_element.getAttribute("name"); //String language = metadata_element.getAttribute("language"); String mode = metadata_element.getAttribute("mode"); // If mode is overwrite, then remove any previous values for this metadata element. if(metadatum != null) { for(int k = metadatum.length - 1; k >= 0; k--) { if(metadatum[k].getElement().toString().equals(element_str)) { metadatum = ArrayTools.remove(metadatum, k); } } } // Add the new metadata. String value_str = MSMUtils.getValue(metadata_element); // Using the element string and value, retrieve a matching Metadata object from the cache Metadata metadata = (Metadata) GDMManager.self.metadata_cache.get(element_str, value_str); if(metadata != null) { // Retrieve the appropriate element and value Elements ElementWrapper element = MetadataSetManager.self.getElement(element_str); GValueModel model = MetadataSetManager.self.getValueTree(element); GValueNode value; if(model != null) { value = model.getValue(value_str); } else { value = new GValueNode(element_str, value_str); } metadata = new Metadata(element, value); GDMManager.self.metadata_cache.put(element_str, value_str, metadata); } metadatum = ArrayTools.add(metadatum, metadata); } } } } catch (Exception error) { Gatherer.self.printStackTrace(error); } //return metadatum; // Change the Metadata[] into an ArrayList ArrayList result = new ArrayList(); for(int i = 0; i < metadatum.length; i++) { result.add(metadatum[i]); } return result; } /** Determine is this is a valid Greenstone Directory Metadata file. It may of course just be some xml file with the name metadata.xml. */ public boolean isValid() { // Just determine if the doctype is GreenstoneDirectoryMetadata and root node is called DirectoryMetadata. String doctype_name = document.getDoctype().getName(); String root_name = document.getDocumentElement().getTagName(); return (doctype_name.equals("GreenstoneDirectoryMetadata") && root_name.equals("DirectoryMetadata")); } /** Remove the given directory level metadata from this document. All directory level metadata is available under the FileSet with filename '.*' */ public void removeDirectoryMetadata(Metadata metadata) { try { Element fileset_element = getFileSet(DIRECTORY_FILENAME); // Retrieve the Metadata Element for this fileset, and iterate through them looking for the one which we are to remove. Element description_element = (Element) MSMUtils.getNodeFromNamed(fileset_element, "Description"); NodeList metadatas = description_element.getElementsByTagName("Metadata"); for(int j = 0; j < metadatas.getLength(); j++) { Element metadata_element = (Element) metadatas.item(j); String element = metadata_element.getAttribute("name"); String value = MSMUtils.getValue(metadata_element); // See if this is the metadata we wish to remove if(element.equals(metadata.getElement().toString()) && value.equals(metadata.getAbsoluteValue())) { // Remove it description_element.removeChild(metadata_element); } } } catch (Exception error) { Gatherer.printStackTrace(error); } } /** Remove the given metadata from the file specified within this document. */ public void removeMetadata(String filename, Metadata metadata) { } /** @deprecated */ public void save() {} /** @deprecated */ public void setUpToDate(boolean state) {} /** Retrieves the fileset with the desired filename pattern, or creates it if none is available. */ private Element getFileSet(String pattern) { Element fileset; // Retrieve the document element. Element directorymetadata_element = document.getDocumentElement(); // Iterate through the filesets looking for the directory level one. NodeList filesets = directorymetadata_element.getElementsByTagName("FileSet"); for(int i = 0; i < filesets.getLength(); i++) { Element fileset_element = (Element) filesets.item(i); Element filename_element = (Element) MSMUtils.getNodeFromNamed(fileset_element, "FileName"); String filename = MSMUtils.getValue(filename_element); if(name.matches(pattern)) { fileset = fileset_element; } filename = null; filename_element = null; fileset_element = null; } filesets = null; // It doesn't already exist. Add our own. if(fileset == null) { Element filename = document.createElement("FileName"); filename.appendChild(document.createTextNode(pattern)); Element description = document.createElement("Description"); fileset = document.createElement("FileSet"); fileset.appendChild(filename); fileset.appendChild(description); if(directorymetadata_element.hasChildNodes()) { directorymetadata_element.insertBefore(fileset, directorymetadata_element.getFirstChild()); } else { directorymetadata_element.appendChild(fileset); } description = null; filename = null; } directorymetadata_element = null; return fileset; } /** Determines if there is already a metadata assignment with the given element name within the given description element. */ public boolean existsMetadata(Element description, String element_name) { boolean result = false; NodeList metadatas = description.getElementsByTagName("Metadata"); for(int i = 0; !result && i < metadatas.getLength(); i++) { Element metadata = (Element) metadatas.item(i); if(metadata.getAttribute("name").equals(element_name)) { result = true; } } return result; } }