/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package org.fcrepo.server.utilities;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.fcrepo.common.Constants;
import org.fcrepo.common.rdf.RDFName;
import org.fcrepo.server.errors.ObjectIntegrityException;
import org.fcrepo.server.errors.RepositoryConfigurationException;
import org.fcrepo.server.errors.StreamIOException;
import org.fcrepo.utilities.ReadableCharArrayWriter;
import org.fcrepo.utilities.XmlTransformUtility;
import javax.xml.XMLConstants;
/**
* Dublin Core Fields.
*
* @author Chris Wilper
* @version $Id$
*/
public class DCFields
extends DefaultHandler
implements Constants {
private static final char[] TITLE = "title".toCharArray();
private static final char[] CREATOR = "creator".toCharArray();
private static final char[] SUBJECT = "subject".toCharArray();
private static final char[] DESCRIPTION = "description".toCharArray();
private static final char[] PUBLISHER = "publisher".toCharArray();
private static final char[] CONTRIBUTOR = "contributor".toCharArray();
private static final char[] DATE = "date".toCharArray();
private static final char[] TYPE = "type".toCharArray();
private static final char[] FORMAT = "format".toCharArray();
private static final char[] IDENTIFIER = "identifier".toCharArray();
private static final char[] SOURCE = "source".toCharArray();
private static final char[] LANGUAGE = "language".toCharArray();
private static final char[] RELATION = "relation".toCharArray();
private static final char[] COVERAGE = "coverage".toCharArray();
private static final char[] RIGHTS = "rights".toCharArray();
private static final char[] XML_OPEN = xmlOpen();
private static final char[] XML_CLOSE = "</oai_dc:dc>\n".toCharArray();
private static final char[] DC_OPEN_ELEMENT_PREFIX =
" <dc:".toCharArray();
private static final char[] DC_CLOSE_ELEMENT_PREFIX =
"</dc:".toCharArray();
private static final char[] XML_LANG_START =
" xml:lang=\"".toCharArray();
private static final char[] BRACKET_NEWLINE =
new char[]{'>','\n'};
private ArrayList<DCField> m_titles = null;
private ArrayList<DCField> m_creators = null;
private ArrayList<DCField> m_subjects = null;
private ArrayList<DCField> m_descriptions = null;
private ArrayList<DCField> m_publishers = null;
private ArrayList<DCField> m_contributors = null;
private ArrayList<DCField> m_dates = null;
private ArrayList<DCField> m_types = null;
private ArrayList<DCField> m_formats = null;
private ArrayList<DCField> m_identifiers = null;
private ArrayList<DCField> m_sources = null;
private ArrayList<DCField> m_languages = null;
private ArrayList<DCField> m_relations = null;
private ArrayList<DCField> m_coverages = null;
private ArrayList<DCField> m_rights = null;
private StringBuffer m_currentContent;
private String m_lang;
public DCFields() {}
public DCFields(InputStream in)
throws RepositoryConfigurationException, ObjectIntegrityException,
StreamIOException {
try {
XmlTransformUtility.parseWithoutValidating(in, this);
} catch (SAXException saxe) {
throw new ObjectIntegrityException("Parse error parsing DC XML Metadata: "
+ saxe.getMessage());
} catch (IOException ioe) {
throw new StreamIOException("Stream error parsing DC XML Metadata: "
+ ioe.getMessage());
}
}
@Override
public void startElement(String uri,
String localName,
String qName,
Attributes attrs) {
m_currentContent = new StringBuffer();
m_lang = attrs.getValue(XMLConstants.XML_NS_URI, "lang");
}
@Override
public void characters(char[] ch, int start, int length) {
m_currentContent.append(ch, start, length);
}
@Override
public void endElement(String uri, String localName, String qName) {
if (localName.equals("title")) {
titles().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("creator")) {
creators().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("subject")) {
subjects().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("description")) {
descriptions().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("publisher")) {
publishers().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("contributor")) {
contributors().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("date")) {
dates().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("type")) {
types().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("format")) {
formats().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("identifier")) {
identifiers().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("source")) {
sources().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("language")) {
languages().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("relation")) {
relations().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("coverage")) {
coverages().add(new DCField(m_currentContent.toString().trim(), m_lang));
} else if (localName.equals("rights")) {
rights().add(new DCField(m_currentContent.toString().trim(), m_lang));
}
}
/**
* Returns a Map with RDFName keys, each value containing List of String
* values for that field.
*/
public Map<RDFName, List<DCField>> getMap() {
Map<RDFName, List<DCField>> map = new HashMap<RDFName, List<DCField>>(15);
if (m_titles != null) map.put(DC.TITLE, m_titles);
if (m_creators != null) map.put(DC.CREATOR, m_creators);
if (m_subjects != null) map.put(DC.SUBJECT, m_subjects);
if (m_descriptions != null) map.put(DC.DESCRIPTION, m_descriptions);
if (m_publishers != null) map.put(DC.PUBLISHER, m_publishers);
if (m_contributors != null) map.put(DC.CONTRIBUTOR, m_contributors);
if (m_dates != null) map.put(DC.DATE, m_dates);
if (m_types != null) map.put(DC.TYPE, m_types);
if (m_formats != null) map.put(DC.FORMAT, m_formats);
if (m_identifiers != null) map.put(DC.IDENTIFIER, m_identifiers);
if (m_sources != null) map.put(DC.SOURCE, m_sources);
if (m_languages != null) map.put(DC.LANGUAGE, m_languages);
if (m_relations != null) map.put(DC.RELATION, m_relations);
if (m_coverages != null) map.put(DC.COVERAGE, m_coverages);
if (m_rights != null) map.put(DC.RIGHTS, m_rights);
return map;
}
public List<DCField> titles() {
if (m_titles == null) m_titles = new ArrayList<DCField>(2);
return m_titles;
}
public List<DCField> creators() {
if (m_creators == null) m_creators = new ArrayList<DCField>(2);
return m_creators;
}
public List<DCField> subjects() {
if (m_subjects == null) m_subjects = new ArrayList<DCField>(2);
return m_subjects;
}
public List<DCField> descriptions() {
if (m_descriptions == null) m_descriptions = new ArrayList<DCField>(2);
return m_descriptions;
}
public List<DCField> publishers() {
if (m_publishers == null) m_publishers = new ArrayList<DCField>(2);
return m_publishers;
}
public List<DCField> contributors() {
if (m_contributors == null) m_contributors = new ArrayList<DCField>(2);
return m_contributors;
}
public List<DCField> dates() {
if (m_dates == null) m_dates = new ArrayList<DCField>(2);
return m_dates;
}
public List<DCField> types() {
if (m_types == null) m_types = new ArrayList<DCField>(2);
return m_types;
}
public List<DCField> formats() {
if (m_formats == null) m_formats = new ArrayList<DCField>(2);
return m_formats;
}
public List<DCField> identifiers() {
if (m_identifiers == null) m_identifiers = new ArrayList<DCField>(2);
return m_identifiers;
}
public List<DCField> sources() {
if (m_sources == null) m_sources = new ArrayList<DCField>(2);
return m_sources;
}
public List<DCField> languages() {
if (m_languages == null) m_languages = new ArrayList<DCField>(2);
return m_languages;
}
public List<DCField> relations() {
if (m_relations == null) m_relations = new ArrayList<DCField>(2);
return m_relations;
}
public List<DCField> coverages() {
if (m_coverages == null) m_coverages = new ArrayList<DCField>(2);
return m_coverages;
}
public List<DCField> rights() {
if (m_rights == null) m_rights = new ArrayList<DCField>(2);
return m_rights;
}
/**
* Get the DCFields as a String in namespace-qualified XML form, matching
* the oai_dc schema.... but without the xml declaration.
*/
public String getAsXML() {
return getAsXML((String)null);
}
public void getAsXML(Writer out) throws IOException {
getAsXML(null, out);
}
/**
* Ensure the dc:identifiers include the pid of the target object
* @param targetPid
* @return String xml
*/
public String getAsXML(String targetPid) {
ReadableCharArrayWriter out = new ReadableCharArrayWriter(512);
try {
getAsXML(targetPid, out);
} catch (IOException wonthappen) {
throw new RuntimeException(wonthappen);
}
return out.getString();
}
public void getAsXML(String targetPid, Writer out) throws IOException {
boolean addPid = (targetPid != null);
if (addPid) {
for (DCField dcField : identifiers()) {
if (dcField.getValue().equals(targetPid)) {
addPid = false;
}
}
}
out.write(XML_OPEN);
appendXML(m_titles, TITLE, out);
appendXML(m_creators, CREATOR, out);
appendXML(m_subjects, SUBJECT, out);
appendXML(m_descriptions, DESCRIPTION, out);
appendXML(m_publishers, PUBLISHER, out);
appendXML(m_contributors, CONTRIBUTOR, out);
appendXML(m_dates, DATE, out);
appendXML(m_types, TYPE, out);
appendXML(m_formats, FORMAT, out);
if (addPid) {
appendXML(new DCField(targetPid), IDENTIFIER, out);
}
appendXML(m_identifiers, IDENTIFIER, out);
appendXML(m_sources, SOURCE, out);
appendXML(m_languages, LANGUAGE, out);
appendXML(m_relations, RELATION, out);
appendXML(m_coverages, COVERAGE, out);
appendXML(m_rights, RIGHTS, out);
out.write(XML_CLOSE);
}
private void appendXML(List<DCField> values, char[] name, Writer out)
throws IOException {
if (values == null || values.size() == 0) return;
for (DCField value : values) {
appendXML(value, name, out);
}
}
private void appendXML(DCField value, char[] name, Writer out)
throws IOException {
out.write(DC_OPEN_ELEMENT_PREFIX);
out.write(name);
if (value.getLang() != null) {
out.write(XML_LANG_START);
out.append(value.getLang()).append('"');
}
out.append('>');
StreamUtility.enc(value.getValue(), out);
out.write(DC_CLOSE_ELEMENT_PREFIX);
out.write(name);
out.write(BRACKET_NEWLINE);
}
private static final char[] xmlOpen() {
return ("<" + OAI_DC.prefix + ":dc" + " xmlns:" + OAI_DC.prefix
+ "=\"" + OAI_DC.uri + "\"" + "\nxmlns:" + DC.prefix + "=\""
+ DC.uri + "\"\nxmlns:xsi=\"" + XSI.uri
+ "\"\nxsi:schemaLocation=\"" + OAI_DC.uri + " "
+ OAI_DC2_0.xsdLocation + "\">\n").toCharArray();
}
}