Package org.fcrepo.server.storage.translation

Source Code of org.fcrepo.server.storage.translation.TestXMLDODeserializer

/* 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.storage.translation;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

import java.lang.reflect.Field;

import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;

import org.jrdf.graph.URIReference;

import org.junit.Test;

import org.fcrepo.server.errors.ObjectIntegrityException;
import org.fcrepo.server.errors.StreamIOException;
import org.fcrepo.server.storage.translation.DODeserializer;
import org.fcrepo.server.storage.translation.DOSerializer;
import org.fcrepo.server.storage.translation.DOTranslationUtility;
import org.fcrepo.server.storage.types.AuditRecord;
import org.fcrepo.server.storage.types.BasicDigitalObject;
import org.fcrepo.server.storage.types.Datastream;
import org.fcrepo.server.storage.types.DatastreamXMLMetadata;
import org.fcrepo.server.storage.types.DigitalObject;
import org.fcrepo.server.storage.types.Disseminator;

import static org.fcrepo.common.Models.FEDORA_OBJECT_3_0;
import static org.fcrepo.common.Models.SERVICE_DEFINITION_3_0;
import static org.fcrepo.common.Models.SERVICE_DEPLOYMENT_3_0;
import static org.fcrepo.server.storage.translation.DOTranslationUtility.DESERIALIZE_INSTANCE;
import static org.fcrepo.server.storage.translation.DOTranslationUtility.SERIALIZE_STORAGE_INTERNAL;



/**
* Common unit tests and utility methods for XML-based deserializers.
*
* @author Chris Wilper
*/
@SuppressWarnings("deprecation")
public abstract class TestXMLDODeserializer
        extends TranslationTest {

    /** The deserializer to test. */
    protected final DODeserializer m_deserializer;

    /** The associated (separately unit-tested) serializer. */
    protected final DOSerializer m_serializer;

    TestXMLDODeserializer(DODeserializer deserializer, DOSerializer serializer) {
        m_deserializer = deserializer;
        m_serializer = serializer;
        if (System.getProperty("fedora.hostname") == null) {
            System.setProperty("fedora.hostname","localhost");
        }
        if (System.getProperty("fedora.port") == null) {
            System.setProperty("fedora.port","1024");
        }
        if (System.getProperty("fedora.appServerContext") == null) {
            System.setProperty("fedora.appServerContext","fedora");
        }
    }

    //---
    // Tests
    //---

    @Test
    public void testDeserializeSimpleDataObject() {
        doSimpleTest(FEDORA_OBJECT_3_0);
    }

    @Test
    public void testDeserializeSimpleSDepObject() {
        doSimpleTest(SERVICE_DEPLOYMENT_3_0);
    }

    @Test
    public void testDeserializeSimpleSDefObject() {
        doSimpleTest(SERVICE_DEFINITION_3_0);
    }

    @Test
    public void testTwoInlineDatastreams() {
        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);

        DigitalObject result = doDeserializeOrFail(obj);
        int numDatastreams = 0;
        Iterator<String> iter = result.datastreamIdIterator();
        while (iter.hasNext()) {
            iter.next();
            numDatastreams++;
        }

        /* 3 datastreams: ds1, ds2, rels-ext */
        assertEquals(3, numDatastreams);
        assertTrue(result.datastreams(dsID1).iterator().hasNext());
        assertTrue(result.datastreams(dsID2).iterator().hasNext());
    }

    /**
     * Tests for deterministic inline-XML content between generations. Addresses
     * bug #1771136: inlineXML would increase in size between copy generations
     * due to added whitespace.
     *
     * @throws Exception
     */
    @Test
    public void testInlineXMLCopyIntegrity() throws Exception {

        DigitalObject original = createTestObject(FEDORA_OBJECT_3_0);
        final String dsID1 = "DS1";

        /* Populate the object with a test datastream and serialize */
        DatastreamXMLMetadata ds1 = createXDatastream(dsID1);
        original.addDatastreamVersion(ds1, true);

        DigitalObject copy = translatedCopy(original);
        DigitalObject copyOfCopy = translatedCopy(copy);

        DatastreamXMLMetadata ds1copy =
                (DatastreamXMLMetadata) copy.datastreams(dsID1).iterator()
                        .next();
        DatastreamXMLMetadata ds1copyOfCopy =
                (DatastreamXMLMetadata) copyOfCopy.datastreams(dsID1)
                        .iterator().next();

        assertEquals("Length of XML datastream copies is not deterministic!",
                     ds1copy.xmlContent.length,
                     ds1copyOfCopy.xmlContent.length);
    }

    @Test
    public void testAuditDatastream() throws Exception {
        AuditRecord record = new AuditRecord();
        record.action = "modifyDatastreamByReference";
        record.componentID = "DRAWING-ICON";
        record.date = new Date(0L);
        record.id = "AUDREC1";
        record.justification = "malice";
        record.processType = "Fedora API-M";
        record.responsibility = "fedoraAdmin";

        DigitalObject original = createTestObject(FEDORA_OBJECT_3_0);
        original.getAuditRecords().add(record);

        // serialize to file
        File temp = File.createTempFile("audit", ".xml");
        OutputStream out = new FileOutputStream(temp);
        m_serializer.serialize(original, out, "utf-8", DOTranslationUtility.SERIALIZE_EXPORT_PUBLIC);
        out.close();

        // deserialize
        DigitalObject candidate = new BasicDigitalObject();
        InputStream in = new FileInputStream(temp);
        m_deserializer.deserialize(in, candidate, "utf-8", DOTranslationUtility.DESERIALIZE_INSTANCE);
        List<AuditRecord> a1 = original.getAuditRecords();
        List<AuditRecord> a2 = candidate.getAuditRecords();
        assertEquals(a1.size(), a2.size());
        for (int i = 0; i < a1.size(); i++) {
            assertEquals(a1.get(i).action, a2.get(i).action);
            assertEquals(a1.get(i).componentID, a2.get(i).componentID);
            assertEquals(a1.get(i).date, a2.get(i).date);
            assertEquals(a1.get(i).id, a2.get(i).id);
            assertEquals(a1.get(i).justification, a2.get(i).justification);
            assertEquals(a1.get(i).processType, a2.get(i).processType);
            assertEquals(a1.get(i).responsibility, a2.get(i).responsibility);
        }

        temp.delete();
    }

    /** Tests the serializers/deserializers when faced with null object property values.
     * <p>
     * Currently, this test assures that null iproperty values are handled consistently
     * among serializers and deserializers.   The expected behaviour is a bit un-intuitive,
     * but represents the "status quo" that satisfies existing server code:
     * <dl>
     * <dt>CreatedDate, LastModifiedDate, External properties</dt>
     * <dd>Null value should be interpreted as null</dd>
     * <dt>Label, OwnerId</dt>
     * <dd>Null value should be interpreted as an empty string ("")</dd>
     * <dt>State</dt>
     * <dd>Null value should be interpreted as "Active"</dd>
     * </dl>
     * </p>
     */
    @Test
    public void testNullObjectProperties() {
        final String EXT_PROP = "http://example.org/test";
        DigitalObject input = createTestObject(FEDORA_OBJECT_3_0);
        input.setCreateDate(null);
        input.setLastModDate(null);
        input.setLabel(null);
        input.setOwnerId(null);
        input.setState(null);
        input.setExtProperty(EXT_PROP, null);

        DigitalObject obj = doDeserializeOrFail(input);

        assertNull("Create date should be null", obj.getCreateDate());
        assertNull("LastMod date should be null", obj.getLastModDate());
        assertEquals("Null label should be interpreted as empty string", "", obj.getLabel());
        assertEquals("Null ownerid should be interpreted as empty string", "", obj.getOwnerId());
        assertEquals("Null state should be interpreted as active", "A", obj.getState());
        assertNull("Ext property should be null", obj.getExtProperty(EXT_PROP));
    }

    /** Tests the serializers/deserializers when faced with empty ("") object property values.
     * <p>
     * Currently, this test assures that empty string property values are handled consistently
     * among serializers and deserializers.   The expected behaviour is as follows:
     * <dl>
     * <dt>Label, Ownerid, External properties</dt>
     * <dd>Empty string value should be interpreted the empty string ("")</dd>
     * <dt>State</dt>
     * <dd>Empty string values should be interpreted as "Active"</dd>
     * </dl>
     * </p>
     */
    @Test
    public void testEmptyObjectProperties() {
        final String EXT_PROP_SUPPORTED = "http://example.org/ext-supported";
        final String EXT_PROP = "http://example.org/test";
        DigitalObject input = createTestObject(FEDORA_OBJECT_3_0);
        input.setLabel("");
        input.setOwnerId("");
        //input.setState("");
        input.setExtProperty(EXT_PROP_SUPPORTED, "true");
        input.setExtProperty(EXT_PROP, "");
        DigitalObject obj = doDeserializeOrFail(input);

        assertEquals("Empty label should remain empty", "", obj.getLabel());
        assertEquals("Empty Ownerid should remain empty", "", obj.getOwnerId());
        assertEquals("Empty State should be interpreted as active", "A", obj.getState());

        /* Some formats (METS) don't support ext. properties */
        if ("true".equals(obj.getExtProperty(EXT_PROP_SUPPORTED))) {
            assertEquals("Empty Ext property should remain empty", "", obj.getExtProperty(EXT_PROP));
        }
    }

    @Test
    public void testFedoraLocalServerSubstitution() {

        DigitalObject o = createTestObject(SERVICE_DEPLOYMENT_3_0);
        DatastreamXMLMetadata ds1 = createXDatastream("WSDL");
        ds1.xmlContent = "<test>http://local.fedora.server/</test>".getBytes();

        o.addDatastreamVersion(ds1, false);

        DigitalObject processed = doDeserializeOrFail(o);

        DatastreamXMLMetadata ds1proc =
                (DatastreamXMLMetadata) processed.datastreams("WSDL")
                        .iterator().next();

        Iterator<String> ids = processed.datastreamIdIterator();

        String content = new String(ds1proc.xmlContent);
        assertFalse(content.contains("local.fedora.server"));
        assertTrue(content.contains("http"));
    }

    /**
     * Copies of an object by deserializing and re-serializing. In theory, there
     * should be no difference between copy generations..
     *
     * @param original
     *        Object to copy
     * @return Copy formed by serializing and de-serializing the original.
     * @throws UnsupportedEncodingException
     * @throws ObjectIntegrityException
     * @throws StreamIOException
     */
    private DigitalObject translatedCopy(DigitalObject original)
            throws UnsupportedEncodingException, ObjectIntegrityException,
            StreamIOException {
        DigitalObject copy = new BasicDigitalObject();
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        m_serializer.serialize(original,
                               out,
                               "UTF-8",
                               SERIALIZE_STORAGE_INTERNAL);
        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
        m_deserializer.deserialize(in,
                                   copy,
                                   "UTF-8",
                                   SERIALIZE_STORAGE_INTERNAL);
        return copy;
    }

    //---
    // Instance helpers
    //---

    protected void doSimpleTest(URIReference... models) {
        DigitalObject input = createTestObject(models);
        DigitalObject obj = doDeserializeOrFail(input);

        for (URIReference model : models) {
            assertTrue("Did not detect that object had model " + model, obj
                    .hasContentModel(model));
        }
        assertEquals(TEST_PID, obj.getPid());
    }

    protected DigitalObject doDeserializeOrFail(DigitalObject obj) {
        DigitalObject result = null;
        try {
            result = doDeserialize(obj);
        } catch (ObjectIntegrityException e) {
            e.printStackTrace();
            fail("Deserializer threw ObjectIntegrityException");
        } catch (StreamIOException e) {
            e.printStackTrace();
            fail("Deserializer threw StreamIOException");
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    protected DigitalObject doDeserialize(DigitalObject obj)
            throws ObjectIntegrityException, StreamIOException {
        /*
         * Make RELS-EXT the last datastream, just to make things trickiest for
         * deserializers (i.e. if serializers need to know relationships before
         * RELS-EXT has been parsed..)
         */
        try {

            Field dsField =
                    BasicDigitalObject.class.getDeclaredField("m_datastreams");
            dsField.setAccessible(true);

            LinkedHashMap<String, List<Datastream>> nativelyOrdered =
                    (LinkedHashMap<String, List<Datastream>>) dsField.get(obj);

            LinkedHashMap<String, List<Datastream>> speciallyOrdered =
                    new LinkedHashMap<String, List<Datastream>>();

            Iterator<String> di = obj.datastreamIdIterator();

            /* Just copy everything EXCEPT rels ext */
            while (di.hasNext()) {
                String id = di.next();
                if (!id.equals("RELS-EXT")) {
                    speciallyOrdered.put(id, nativelyOrdered.get(id));
                }
            }

            /* Put RELS-EXT last, if defined */
            List<Datastream> rels = nativelyOrdered.get("RELS-EXT");
            if (rels != null) {
                speciallyOrdered.put("RELS-EXT", rels);
            }

            dsField.set(obj, speciallyOrdered);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return doDeserialize(getStream(obj));
    }

    protected DigitalObject doDeserialize(InputStream in)
            throws ObjectIntegrityException, StreamIOException {
        BasicDigitalObject obj = new BasicDigitalObject();

        try {
            m_deserializer.deserialize(in, obj, "UTF-8", DESERIALIZE_INSTANCE);
        } catch (UnsupportedEncodingException wontHappen) {
            fail("Deserializer doesn't support UTF-8?!");
        }
        return obj;
    }

    // use the associated serializer to create a stream for the object, or fail
    protected InputStream getStream(DigitalObject obj) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            m_serializer.serialize(obj,
                                   out,
                                   "UTF-8",
                                   SERIALIZE_STORAGE_INTERNAL);
        } catch (Exception e) {
            e.printStackTrace();
            fail("Failed to serialize test object for deserialization test");
        }
        return new ByteArrayInputStream(out.toByteArray());
    }

    protected void doTestTwoDisseminators() {
        DigitalObject obj = createTestObject(FEDORA_OBJECT_3_0);

        final String dissID1 = "DISS1";
        Disseminator diss1 = createDisseminator(dissID1, 1);

        final String dissID2 = "DISS2";
        Disseminator diss2 = createDisseminator(dissID2, 1);

        obj.disseminators(dissID1).add(diss1);
        obj.disseminators(dissID2).add(diss2);

        DigitalObject result = doDeserializeOrFail(obj);
        int numDisseminators = 0;
        Iterator<String> iter = result.disseminatorIdIterator();
        while (iter.hasNext()) {
            iter.next();
            numDisseminators++;
        }
        assertEquals(2, numDisseminators);
        assertEquals(1, result.disseminators(dissID1).size());
        assertEquals(1, result.disseminators(dissID2).size());
    }

}
TOP

Related Classes of org.fcrepo.server.storage.translation.TestXMLDODeserializer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.