org.dspace.app.util.DCInputsReader Maven / Gradle / Ivy
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.util;
import java.io.File;
import java.util.*;
import org.xml.sax.SAXException;
import org.w3c.dom.*;
import javax.xml.parsers.*;
import org.dspace.content.MetadataSchema;
import org.dspace.core.ConfigurationManager;
/**
* Submission form generator for DSpace. Reads and parses the installation
* form definitions file, input-forms.xml, from the configuration directory.
* A forms definition details the page and field layout of the metadata
* collection pages used by the submission process. Each forms definition
* starts with a unique name that gets associated with that form set.
*
* The file also specifies which collections use which form sets. At a
* minimum, the definitions file must define a default mapping from the
* placeholder collection #0 to the distinguished form 'default'. Any
* collections that use a custom form set are listed paired with the name
* of the form set they use.
*
* The definitions file also may contain sets of value pairs. Each value pair
* will contain one string that the user reads, and a paired string that will
* supply the value stored in the database if its sibling display value gets
* selected from a choice list.
*
* @author Brian S. Hughes
* @version $Revision: 5844 $
*/
public class DCInputsReader
{
/**
* The ID of the default collection. Will never be the ID of a named
* collection
*/
public static final String DEFAULT_COLLECTION = "default";
/** Name of the form definition XML file */
static final String FORM_DEF_FILE = "input-forms.xml";
/** Keyname for storing dropdown value-pair set name */
static final String PAIR_TYPE_NAME = "value-pairs-name";
/** The fully qualified pathname of the form definition XML file */
private String defsFile = ConfigurationManager.getProperty("dspace.dir")
+ File.separator + "config" + File.separator + FORM_DEF_FILE;
/**
* Reference to the collections to forms map, computed from the forms
* definition file
*/
private Map whichForms = null;
/**
* Reference to the forms definitions map, computed from the forms
* definition file
*/
private Map>>> formDefns = null;
/**
* Reference to the value-pairs map, computed from the forms definition file
*/
private Map> valuePairs = null; // Holds display/storage pairs
/**
* Mini-cache of last DCInputSet requested. If submissions are not typically
* form-interleaved, there will be a modest win.
*/
private DCInputSet lastInputSet = null;
/**
* Parse an XML encoded submission forms template file, and create a hashmap
* containing all the form information. This hashmap will contain three top
* level structures: a map between collections and forms, the definition for
* each page of each form, and lists of pairs of values that populate
* selection boxes.
*/
public DCInputsReader()
throws DCInputsReaderException
{
buildInputs(defsFile);
}
public DCInputsReader(String fileName)
throws DCInputsReaderException
{
buildInputs(fileName);
}
private void buildInputs(String fileName)
throws DCInputsReaderException
{
whichForms = new HashMap();
formDefns = new HashMap>>>();
valuePairs = new HashMap>();
String uri = "file:" + new File(fileName).getAbsolutePath();
try
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder db = factory.newDocumentBuilder();
Document doc = db.parse(uri);
doNodes(doc);
checkValues();
}
catch (FactoryConfigurationError fe)
{
throw new DCInputsReaderException("Cannot create Submission form parser",fe);
}
catch (Exception e)
{
throw new DCInputsReaderException("Error creating submission forms: "+e);
}
}
public Iterator getPairsNameIterator()
{
return valuePairs.keySet().iterator();
}
public List getPairs(String name)
{
return valuePairs.get(name);
}
/**
* Returns the set of DC inputs used for a particular collection, or the
* default set if no inputs defined for the collection
*
* @param collectionHandle
* collection's unique Handle
* @return DC input set
* @throws DCInputsReaderException
* if no default set defined
*/
public DCInputSet getInputs(String collectionHandle)
throws DCInputsReaderException
{
String formName = whichForms.get(collectionHandle);
if (formName == null)
{
formName = whichForms.get(DEFAULT_COLLECTION);
}
if (formName == null)
{
throw new DCInputsReaderException("No form designated as default");
}
// check mini-cache, and return if match
if ( lastInputSet != null && lastInputSet.getFormName().equals( formName ) )
{
return lastInputSet;
}
// cache miss - construct new DCInputSet
List>> pages = formDefns.get(formName);
if ( pages == null )
{
throw new DCInputsReaderException("Missing the " + formName + " form");
}
lastInputSet = new DCInputSet(formName, pages, valuePairs);
return lastInputSet;
}
/**
* Return the number of pages the inputs span for a desginated collection
* @param collectionHandle collection's unique Handle
* @return number of pages of input
* @throws DCInputsReaderException if no default set defined
*/
public int getNumberInputPages(String collectionHandle)
throws DCInputsReaderException
{
return getInputs(collectionHandle).getNumberPages();
}
/**
* Process the top level child nodes in the passed top-level node. These
* should correspond to the collection-form maps, the form definitions, and
* the display/storage word pairs.
*/
private void doNodes(Node n)
throws SAXException, DCInputsReaderException
{
if (n == null)
{
return;
}
Node e = getElement(n);
NodeList nl = e.getChildNodes();
int len = nl.getLength();
boolean foundMap = false;
boolean foundDefs = false;
for (int i = 0; i < len; i++)
{
Node nd = nl.item(i);
if ((nd == null) || isEmptyTextNode(nd))
{
continue;
}
String tagName = nd.getNodeName();
if (tagName.equals("form-map"))
{
processMap(nd);
foundMap = true;
}
else if (tagName.equals("form-definitions"))
{
processDefinition(nd);
foundDefs = true;
}
else if (tagName.equals("form-value-pairs"))
{
processValuePairs(nd);
}
// Ignore unknown nodes
}
if (!foundMap)
{
throw new DCInputsReaderException("No collection to form map found");
}
if (!foundDefs)
{
throw new DCInputsReaderException("No form definition found");
}
}
/**
* Process the form-map section of the XML file.
* Each element looks like:
*
* Extract the collection handle and form name, put name in hashmap keyed
* by the collection handle.
*/
private void processMap(Node e)
throws SAXException
{
NodeList nl = e.getChildNodes();
int len = nl.getLength();
for (int i = 0; i < len; i++)
{
Node nd = nl.item(i);
if (nd.getNodeName().equals("name-map"))
{
String id = getAttribute(nd, "collection-handle");
String value = getAttribute(nd, "form-name");
String content = getValue(nd);
if (id == null)
{
throw new SAXException("name-map element is missing collection-handle attribute");
}
if (value == null)
{
throw new SAXException("name-map element is missing form-name attribute");
}
if (content != null && content.length() > 0)
{
throw new SAXException("name-map element has content, it should be empty.");
}
whichForms.put(id, value);
} // ignore any child node that isn't a "name-map"
}
}
/**
* Process the form-definitions section of the XML file. Each element is
* formed thusly: Each pages
* subsection is formed: ...fields... Each field
* is formed from: dc-element, dc-qualifier, label, hint, input-type name,
* required text, and repeatable flag.
*/
private void processDefinition(Node e)
throws SAXException, DCInputsReaderException
{
int numForms = 0;
NodeList nl = e.getChildNodes();
int len = nl.getLength();
for (int i = 0; i < len; i++)
{
Node nd = nl.item(i);
// process each form definition
if (nd.getNodeName().equals("form"))
{
numForms++;
String formName = getAttribute(nd, "name");
if (formName == null)
{
throw new SAXException("form element has no name attribute");
}
List>> pages = new ArrayList>>(); // the form contains pages
formDefns.put(formName, pages);
NodeList pl = nd.getChildNodes();
int lenpg = pl.getLength();
for (int j = 0; j < lenpg; j++)
{
Node npg = pl.item(j);
// process each page definition
if (npg.getNodeName().equals("page"))
{
String pgNum = getAttribute(npg, "number");
if (pgNum == null)
{
throw new SAXException("Form " + formName + " has no identified pages");
}
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy