/* 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 fedora.server.storage.translation;
import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.xml.transform.TransformerException;
import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import org.custommonkey.xmlunit.NamespaceContext;
import org.custommonkey.xmlunit.SimpleNamespaceContext;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.exceptions.XpathException;
import org.jrdf.graph.Literal;
import org.jrdf.graph.ObjectNode;
import org.jrdf.graph.PredicateNode;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import fedora.common.rdf.RDFName;
import fedora.server.storage.RDFRelationshipReader;
import fedora.server.storage.types.DatastreamXMLMetadata;
import fedora.server.storage.types.DigitalObject;
import fedora.server.storage.types.RelationshipTuple;
import static fedora.common.Constants.FOXML;
import static fedora.common.Constants.MODEL;
import static fedora.common.Constants.RDF;
import static fedora.common.Models.CONTENT_MODEL_3_0;
import static fedora.common.Models.FEDORA_OBJECT_3_0;
import static fedora.common.Models.SERVICE_DEFINITION_3_0;
import static fedora.common.Models.SERVICE_DEPLOYMENT_3_0;
/**
* Common unit tests for FOXML serializers.
*
* @author Chris Wilper
*/
public abstract class TestFOXMLDOSerializer
extends TestXMLDOSerializer {
protected static final String ROOT_PATH = "/" + FOXML.DIGITAL_OBJECT.qName;
protected static final String PROPERTIES_PATH =
ROOT_PATH + "/" + FOXML.OBJECT_PROPERTIES.qName;
protected static final String PROPERTY_PATH =
PROPERTIES_PATH + "/" + FOXML.PROPERTY.qName;
protected static final String DATASTREAM_PATH =
ROOT_PATH + "/" + FOXML.DATASTREAM.qName;
TestFOXMLDOSerializer(DOSerializer serializer) {
super(serializer);
}
//---
// Setup/Teardown
//---
@Before
@Override
public void setUp() {
super.setUp();
Map<String, String> nsMap = new HashMap<String, String>();
nsMap.put(FOXML.prefix, FOXML.uri);
NamespaceContext ctx = new SimpleNamespaceContext(nsMap);
XMLUnit.setXpathNamespaceContext(ctx);
}
@Override
@After
public void tearDown() {
XMLUnit.setXpathNamespaceContext(SimpleNamespaceContext.EMPTY_CONTEXT);
}
//---
// Tests
//---
@Test
public void testPIDAttribute() throws TransformerException, XpathException {
DigitalObject obj = createTestObject(FEDORA_OBJECT_3_0);
Document xml = doSerializeOrFail(obj);
assertXpathExists(ROOT_PATH + "[@PID='" + TEST_PID + "']", xml);
}
@Test
public void testCommonFedoraObjectTypes() throws TransformerException {
DigitalObject obj;
Document xml;
obj = createTestObject(FEDORA_OBJECT_3_0);
xml = doSerializeOrFail(obj);
checkRelationships(xml, MODEL.HAS_MODEL, FEDORA_OBJECT_3_0);
obj = createTestObject(CONTENT_MODEL_3_0);
xml = doSerializeOrFail(obj);
checkRelationships(xml,
MODEL.HAS_MODEL,
CONTENT_MODEL_3_0);
obj = createTestObject(SERVICE_DEFINITION_3_0);
xml = doSerializeOrFail(obj);
checkRelationships(xml,
MODEL.HAS_MODEL,
SERVICE_DEFINITION_3_0);
obj = createTestObject(SERVICE_DEPLOYMENT_3_0);
xml = doSerializeOrFail(obj);
checkRelationships(xml,
MODEL.HAS_MODEL,
SERVICE_DEPLOYMENT_3_0);
}
@Test
public void testTwoInlineDatastreams() throws TransformerException, XpathException {
DigitalObject obj = createTestObject(FEDORA_OBJECT_3_0);
final String dsID1 = "DS1";
DatastreamXMLMetadata ds1 = createXDatastream(dsID1);
final String dsID2 = "DS2";
DatastreamXMLMetadata ds2 = createXDatastream(dsID2);
obj.addDatastreamVersion(ds1, true);
obj.addDatastreamVersion(ds2, true);
Document xml = doSerializeOrFail(obj);
/* 3 datastreams: rels-ext, ds1, and ds2 */
assertXpathEvaluatesTo("3", "count(" + DATASTREAM_PATH + ")", xml);
}
//---
// Instance helpers
//---
protected void checkProperty(Document xml, RDFName name, String value)
throws TransformerException, XpathException {
assertXpathExists(PROPERTY_PATH + "[@NAME='" + name.uri + "'"
+ " and @VALUE='" + value + "']", xml);
}
protected void checkRelationships(Document xml,
PredicateNode pred,
ObjectNode... nodes) {
NodeList streams =
xml.getElementsByTagNameNS(FOXML.DATASTREAM.namespace.uri,
FOXML.DATASTREAM_VERSION.localName);
if (streams.getLength() == 0) {
fail("No relationships found. Serializer "
+ m_serializer.getClass().getName());
}
/*
* Get the latest RELS-EXT, assuming that the latest has the maximal
* datastream version ID...
*/
Element lastDS = null;
String maxId = "";
for (int i = 0; i < streams.getLength(); i++) {
Element ds = (Element) streams.item(i);
String id = ds.getAttribute("ID");
if (id.startsWith("RELS-EXT") && id.compareTo(maxId) > 0) {
maxId = id;
lastDS = ds;
}
}
NodeList rdf = lastDS.getElementsByTagNameNS(RDF.uri, "RDF");
if (rdf.getLength() != 1) {
fail("Could not locate valid RDF");
}
Element rdfRels = (Element) rdf.item(0);
Set<RelationshipTuple> rels = new HashSet<RelationshipTuple>();
try {
StringWriter sout = new StringWriter();
OutputFormat formatter = new OutputFormat();
formatter.setEncoding("UTF-8"); // is the default
XMLSerializer serializer = new XMLSerializer(sout, formatter);
serializer.serialize(rdfRels);
rels =
RDFRelationshipReader
.readRelationships(new ByteArrayInputStream(sout
.toString().getBytes()));
} catch (Exception e) {
throw new RuntimeException(e);
}
/* Finally, check the relationships the hard way */
for (ObjectNode value : nodes) {
boolean found = false;
for (RelationshipTuple rel : rels) {
if (rel.predicate.equals(pred.toString())
&& rel.object.equals(value.toString())) {
if ((value instanceof Literal) == rel.isLiteral)
found = true;
break;
}
}
if (!found) {
fail("Failed to find relationship " + pred + " = " + value);
}
}
}
}